Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 #include "base/threading/sequenced_worker_pool.h" | 5 #include "base/threading/sequenced_worker_pool.h" |
| 6 | 6 |
| 7 #include <list> | 7 #include <list> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 // This lock protects |everything in this class|. Do not read or modify | 382 // This lock protects |everything in this class|. Do not read or modify |
| 383 // anything without holding this lock. Do not block while holding this | 383 // anything without holding this lock. Do not block while holding this |
| 384 // lock. | 384 // lock. |
| 385 mutable Lock lock_; | 385 mutable Lock lock_; |
| 386 | 386 |
| 387 // Condition variable that is waited on by worker threads until new | 387 // Condition variable that is waited on by worker threads until new |
| 388 // tasks are posted or shutdown starts. | 388 // tasks are posted or shutdown starts. |
| 389 ConditionVariable has_work_cv_; | 389 ConditionVariable has_work_cv_; |
| 390 | 390 |
| 391 // Condition variable that is waited on by non-worker threads (in | 391 // Condition variable that is waited on by non-worker threads (in |
| 392 // FlushForTesting()) until IsIdle() goes to true. | 392 // FlushForTesting()) until IsIdle() goes to true or Shutdown completes. |
| 393 ConditionVariable is_idle_cv_; | 393 ConditionVariable is_idle_cv_; |
| 394 | 394 |
| 395 // Condition variable that is waited on by non-worker threads (in | 395 // Condition variable that is waited on by non-worker threads (in |
| 396 // Shutdown()) until CanShutdown() goes to true. | 396 // Shutdown()) until CanShutdown() goes to true. |
| 397 ConditionVariable can_shutdown_cv_; | 397 ConditionVariable can_shutdown_cv_; |
| 398 | 398 |
| 399 // The maximum number of worker threads we'll create. | 399 // The maximum number of worker threads we'll create. |
| 400 const size_t max_threads_; | 400 const size_t max_threads_; |
| 401 | 401 |
| 402 const std::string thread_name_prefix_; | 402 const std::string thread_name_prefix_; |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 603 bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread( | 603 bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread( |
| 604 SequenceToken sequence_token) const { | 604 SequenceToken sequence_token) const { |
| 605 AutoLock lock(lock_); | 605 AutoLock lock(lock_); |
| 606 ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId()); | 606 ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId()); |
| 607 if (found == threads_.end()) | 607 if (found == threads_.end()) |
| 608 return false; | 608 return false; |
| 609 return found->second->running_sequence().Equals(sequence_token); | 609 return found->second->running_sequence().Equals(sequence_token); |
| 610 } | 610 } |
| 611 | 611 |
| 612 void SequencedWorkerPool::Inner::FlushForTesting() { | 612 void SequencedWorkerPool::Inner::FlushForTesting() { |
| 613 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 613 AutoLock lock(lock_); | 614 AutoLock lock(lock_); |
| 614 while (!IsIdle()) | 615 while (!IsIdle() && !shutdown_called_) |
| 615 is_idle_cv_.Wait(); | 616 is_idle_cv_.Wait(); |
| 616 } | 617 } |
| 617 | 618 |
| 618 void SequencedWorkerPool::Inner::SignalHasWorkForTesting() { | 619 void SequencedWorkerPool::Inner::SignalHasWorkForTesting() { |
| 619 SignalHasWork(); | 620 SignalHasWork(); |
| 620 } | 621 } |
| 621 | 622 |
| 622 void SequencedWorkerPool::Inner::Shutdown( | 623 void SequencedWorkerPool::Inner::Shutdown( |
| 623 int max_new_blocking_tasks_after_shutdown) { | 624 int max_new_blocking_tasks_after_shutdown) { |
| 624 DCHECK_GE(max_new_blocking_tasks_after_shutdown, 0); | 625 DCHECK_GE(max_new_blocking_tasks_after_shutdown, 0); |
| 625 { | 626 { |
| 626 AutoLock lock(lock_); | 627 AutoLock lock(lock_); |
| 627 | 628 |
| 628 if (shutdown_called_) | 629 if (shutdown_called_) |
| 629 return; | 630 return; |
| 630 shutdown_called_ = true; | 631 shutdown_called_ = true; |
|
michaeln
2012/12/21 23:43:19
Hi Fred,
Not sure if you've been following along
| |
| 631 max_blocking_tasks_after_shutdown_ = max_new_blocking_tasks_after_shutdown; | 632 max_blocking_tasks_after_shutdown_ = max_new_blocking_tasks_after_shutdown; |
| 632 | 633 |
| 633 // Tickle the threads. This will wake up a waiting one so it will know that | 634 // Tickle the threads. This will wake up a waiting one so it will know that |
| 634 // it can exit, which in turn will wake up any other waiting ones. | 635 // it can exit, which in turn will wake up any other waiting ones. |
| 635 SignalHasWork(); | 636 SignalHasWork(); |
| 636 | 637 |
| 637 // There are no pending or running tasks blocking shutdown, we're done. | 638 // There are no pending or running tasks blocking shutdown, we're done. |
| 638 if (CanShutdown()) | 639 if (CanShutdown()) { |
| 640 is_idle_cv_.Signal(); | |
| 639 return; | 641 return; |
| 642 } | |
| 640 } | 643 } |
| 641 | 644 |
| 642 // If we're here, then something is blocking shutdown. So wait for | 645 // If we're here, then something is blocking shutdown. So wait for |
| 643 // CanShutdown() to go to true. | 646 // CanShutdown() to go to true. |
| 644 | 647 |
| 645 if (testing_observer_) | 648 if (testing_observer_) |
| 646 testing_observer_->WillWaitForShutdown(); | 649 testing_observer_->WillWaitForShutdown(); |
| 647 | 650 |
| 648 TimeTicks shutdown_wait_begin = TimeTicks::Now(); | 651 TimeTicks shutdown_wait_begin = TimeTicks::Now(); |
| 649 | 652 |
| 650 { | 653 { |
| 651 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 654 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 652 AutoLock lock(lock_); | 655 AutoLock lock(lock_); |
| 653 while (!CanShutdown()) | 656 while (!CanShutdown()) |
| 654 can_shutdown_cv_.Wait(); | 657 can_shutdown_cv_.Wait(); |
| 658 is_idle_cv_.Signal(); | |
| 655 } | 659 } |
| 656 UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime", | 660 UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime", |
| 657 TimeTicks::Now() - shutdown_wait_begin); | 661 TimeTicks::Now() - shutdown_wait_begin); |
| 658 } | 662 } |
| 659 | 663 |
| 660 void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { | 664 void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| 661 { | 665 { |
| 662 AutoLock lock(lock_); | 666 AutoLock lock(lock_); |
| 663 DCHECK(thread_being_created_); | 667 DCHECK(thread_being_created_); |
| 664 thread_being_created_ = false; | 668 thread_being_created_ = false; |
| (...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1152 void SequencedWorkerPool::SignalHasWorkForTesting() { | 1156 void SequencedWorkerPool::SignalHasWorkForTesting() { |
| 1153 inner_->SignalHasWorkForTesting(); | 1157 inner_->SignalHasWorkForTesting(); |
| 1154 } | 1158 } |
| 1155 | 1159 |
| 1156 void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) { | 1160 void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) { |
| 1157 DCHECK(constructor_message_loop_->BelongsToCurrentThread()); | 1161 DCHECK(constructor_message_loop_->BelongsToCurrentThread()); |
| 1158 inner_->Shutdown(max_new_blocking_tasks_after_shutdown); | 1162 inner_->Shutdown(max_new_blocking_tasks_after_shutdown); |
| 1159 } | 1163 } |
| 1160 | 1164 |
| 1161 } // namespace base | 1165 } // namespace base |
| OLD | NEW |