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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 SequenceToken sequence_token, | 274 SequenceToken sequence_token, |
| 275 WorkerShutdown shutdown_behavior, | 275 WorkerShutdown shutdown_behavior, |
| 276 const tracked_objects::Location& from_here, | 276 const tracked_objects::Location& from_here, |
| 277 const Closure& task, | 277 const Closure& task, |
| 278 TimeDelta delay); | 278 TimeDelta delay); |
| 279 | 279 |
| 280 bool RunsTasksOnCurrentThread() const; | 280 bool RunsTasksOnCurrentThread() const; |
| 281 | 281 |
| 282 bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const; | 282 bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const; |
| 283 | 283 |
| 284 void FlushForTesting(); | 284 void CleanupForTesting(); |
| 285 | 285 |
| 286 void SignalHasWorkForTesting(); | 286 void SignalHasWorkForTesting(); |
| 287 | 287 |
| 288 int GetWorkSignalCountForTesting() const; | 288 int GetWorkSignalCountForTesting() const; |
| 289 | 289 |
| 290 void Shutdown(int max_blocking_tasks_after_shutdown); | 290 void Shutdown(int max_blocking_tasks_after_shutdown); |
| 291 | 291 |
| 292 // Runs the worker loop on the background thread. | 292 // Runs the worker loop on the background thread. |
| 293 void ThreadLoop(Worker* this_worker); | 293 void ThreadLoop(Worker* this_worker); |
| 294 | 294 |
| 295 private: | 295 private: |
| 296 enum GetWorkStatus { | 296 enum GetWorkStatus { |
| 297 GET_WORK_FOUND, | 297 GET_WORK_FOUND, |
| 298 GET_WORK_NOT_FOUND, | 298 GET_WORK_NOT_FOUND, |
| 299 GET_WORK_WAIT, | 299 GET_WORK_WAIT, |
| 300 }; | 300 }; |
| 301 | 301 |
| 302 // Returns whether there are no more pending tasks and all threads | 302 enum CleanupState { |
| 303 // are idle. Must be called under lock. | 303 CLEANUP_REQUESTED, |
| 304 bool IsIdle() const; | 304 CLEANUP_WAITING, |
| 305 CLEANUP_RUNNING, | |
| 306 CLEANUP_DONE | |
| 307 }; | |
| 305 | 308 |
| 306 // Called from within the lock, this converts the given token name into a | 309 // Called from within the lock, this converts the given token name into a |
| 307 // token ID, creating a new one if necessary. | 310 // token ID, creating a new one if necessary. |
| 308 int LockedGetNamedTokenID(const std::string& name); | 311 int LockedGetNamedTokenID(const std::string& name); |
| 309 | 312 |
| 310 // Called from within the lock, this returns the next sequence task number. | 313 // Called from within the lock, this returns the next sequence task number. |
| 311 int64 LockedGetNextSequenceTaskNumber(); | 314 int64 LockedGetNextSequenceTaskNumber(); |
| 312 | 315 |
| 313 // Called from within the lock, returns the shutdown behavior of the task | 316 // Called from within the lock, returns the shutdown behavior of the task |
| 314 // running on the currently executing worker thread. If invoked from a thread | 317 // running on the currently executing worker thread. If invoked from a thread |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 327 // filled in the time to wait until the next task to run. In this case, the | 330 // filled in the time to wait until the next task to run. In this case, the |
| 328 // caller should wait the time. | 331 // caller should wait the time. |
| 329 // | 332 // |
| 330 // In any case, the calling code should clear the given | 333 // In any case, the calling code should clear the given |
| 331 // delete_these_outside_lock vector the next time the lock is released. | 334 // delete_these_outside_lock vector the next time the lock is released. |
| 332 // See the implementation for a more detailed description. | 335 // See the implementation for a more detailed description. |
| 333 GetWorkStatus GetWork(SequencedTask* task, | 336 GetWorkStatus GetWork(SequencedTask* task, |
| 334 TimeDelta* wait_time, | 337 TimeDelta* wait_time, |
| 335 std::vector<Closure>* delete_these_outside_lock); | 338 std::vector<Closure>* delete_these_outside_lock); |
| 336 | 339 |
| 340 void HandleCleanup(); | |
| 341 | |
| 337 // Peforms init and cleanup around running the given task. WillRun... | 342 // Peforms init and cleanup around running the given task. WillRun... |
| 338 // returns the value from PrepareToStartAdditionalThreadIfNecessary. | 343 // returns the value from PrepareToStartAdditionalThreadIfNecessary. |
| 339 // The calling code should call FinishStartingAdditionalThread once the | 344 // The calling code should call FinishStartingAdditionalThread once the |
| 340 // lock is released if the return values is nonzero. | 345 // lock is released if the return values is nonzero. |
| 341 int WillRunWorkerTask(const SequencedTask& task); | 346 int WillRunWorkerTask(const SequencedTask& task); |
| 342 void DidRunWorkerTask(const SequencedTask& task); | 347 void DidRunWorkerTask(const SequencedTask& task); |
| 343 | 348 |
| 344 // Returns true if there are no threads currently running the given | 349 // Returns true if there are no threads currently running the given |
| 345 // sequence token. | 350 // sequence token. |
| 346 bool IsSequenceTokenRunnable(int sequence_token_id) const; | 351 bool IsSequenceTokenRunnable(int sequence_token_id) const; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 // This lock protects |everything in this class|. Do not read or modify | 387 // This lock protects |everything in this class|. Do not read or modify |
| 383 // anything without holding this lock. Do not block while holding this | 388 // anything without holding this lock. Do not block while holding this |
| 384 // lock. | 389 // lock. |
| 385 mutable Lock lock_; | 390 mutable Lock lock_; |
| 386 | 391 |
| 387 // Condition variable that is waited on by worker threads until new | 392 // Condition variable that is waited on by worker threads until new |
| 388 // tasks are posted or shutdown starts. | 393 // tasks are posted or shutdown starts. |
| 389 ConditionVariable has_work_cv_; | 394 ConditionVariable has_work_cv_; |
| 390 | 395 |
| 391 // Condition variable that is waited on by non-worker threads (in | 396 // Condition variable that is waited on by non-worker threads (in |
| 392 // FlushForTesting()) until IsIdle() goes to true. | |
| 393 ConditionVariable is_idle_cv_; | |
| 394 | |
| 395 // Condition variable that is waited on by non-worker threads (in | |
| 396 // Shutdown()) until CanShutdown() goes to true. | 397 // Shutdown()) until CanShutdown() goes to true. |
| 397 ConditionVariable can_shutdown_cv_; | 398 ConditionVariable can_shutdown_cv_; |
| 398 | 399 |
| 399 // The maximum number of worker threads we'll create. | 400 // The maximum number of worker threads we'll create. |
| 400 const size_t max_threads_; | 401 const size_t max_threads_; |
| 401 | 402 |
| 402 const std::string thread_name_prefix_; | 403 const std::string thread_name_prefix_; |
| 403 | 404 |
| 404 // Associates all known sequence token names with their IDs. | 405 // Associates all known sequence token names with their IDs. |
| 405 std::map<std::string, int> named_sequence_tokens_; | 406 std::map<std::string, int> named_sequence_tokens_; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 443 int trace_id_; | 444 int trace_id_; |
| 444 | 445 |
| 445 // Set when Shutdown is called and no further tasks should be | 446 // Set when Shutdown is called and no further tasks should be |
| 446 // allowed, though we may still be running existing tasks. | 447 // allowed, though we may still be running existing tasks. |
| 447 bool shutdown_called_; | 448 bool shutdown_called_; |
| 448 | 449 |
| 449 // The number of new BLOCK_SHUTDOWN tasks that may be posted after Shudown() | 450 // The number of new BLOCK_SHUTDOWN tasks that may be posted after Shudown() |
| 450 // has been called. | 451 // has been called. |
| 451 int max_blocking_tasks_after_shutdown_; | 452 int max_blocking_tasks_after_shutdown_; |
| 452 | 453 |
| 454 // State used to cleanup for testing, all guarded by lock_. | |
| 455 CleanupState cleanup_state_; | |
| 456 size_t cleanup_idlers_; | |
| 457 ConditionVariable cleanup_cv_; | |
| 458 | |
| 453 TestingObserver* const testing_observer_; | 459 TestingObserver* const testing_observer_; |
| 454 | 460 |
| 455 DISALLOW_COPY_AND_ASSIGN(Inner); | 461 DISALLOW_COPY_AND_ASSIGN(Inner); |
| 456 }; | 462 }; |
| 457 | 463 |
| 458 // Worker definitions --------------------------------------------------------- | 464 // Worker definitions --------------------------------------------------------- |
| 459 | 465 |
| 460 SequencedWorkerPool::Worker::Worker( | 466 SequencedWorkerPool::Worker::Worker( |
| 461 const scoped_refptr<SequencedWorkerPool>& worker_pool, | 467 const scoped_refptr<SequencedWorkerPool>& worker_pool, |
| 462 int thread_number, | 468 int thread_number, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 486 | 492 |
| 487 SequencedWorkerPool::Inner::Inner( | 493 SequencedWorkerPool::Inner::Inner( |
| 488 SequencedWorkerPool* worker_pool, | 494 SequencedWorkerPool* worker_pool, |
| 489 size_t max_threads, | 495 size_t max_threads, |
| 490 const std::string& thread_name_prefix, | 496 const std::string& thread_name_prefix, |
| 491 TestingObserver* observer) | 497 TestingObserver* observer) |
| 492 : worker_pool_(worker_pool), | 498 : worker_pool_(worker_pool), |
| 493 last_sequence_number_(0), | 499 last_sequence_number_(0), |
| 494 lock_(), | 500 lock_(), |
| 495 has_work_cv_(&lock_), | 501 has_work_cv_(&lock_), |
| 496 is_idle_cv_(&lock_), | |
| 497 can_shutdown_cv_(&lock_), | 502 can_shutdown_cv_(&lock_), |
| 498 max_threads_(max_threads), | 503 max_threads_(max_threads), |
| 499 thread_name_prefix_(thread_name_prefix), | 504 thread_name_prefix_(thread_name_prefix), |
| 500 thread_being_created_(false), | 505 thread_being_created_(false), |
| 501 waiting_thread_count_(0), | 506 waiting_thread_count_(0), |
| 502 blocking_shutdown_thread_count_(0), | 507 blocking_shutdown_thread_count_(0), |
| 503 next_sequence_task_number_(0), | 508 next_sequence_task_number_(0), |
| 504 blocking_shutdown_pending_task_count_(0), | 509 blocking_shutdown_pending_task_count_(0), |
| 505 trace_id_(0), | 510 trace_id_(0), |
| 506 shutdown_called_(false), | 511 shutdown_called_(false), |
| 507 max_blocking_tasks_after_shutdown_(0), | 512 max_blocking_tasks_after_shutdown_(0), |
| 513 cleanup_state_(CLEANUP_DONE), | |
| 514 cleanup_idlers_(0), | |
| 515 cleanup_cv_(&lock_), | |
| 508 testing_observer_(observer) {} | 516 testing_observer_(observer) {} |
| 509 | 517 |
| 510 SequencedWorkerPool::Inner::~Inner() { | 518 SequencedWorkerPool::Inner::~Inner() { |
| 511 // You must call Shutdown() before destroying the pool. | 519 // You must call Shutdown() before destroying the pool. |
| 512 DCHECK(shutdown_called_); | 520 DCHECK(shutdown_called_); |
| 513 | 521 |
| 514 // Need to explicitly join with the threads before they're destroyed or else | 522 // Need to explicitly join with the threads before they're destroyed or else |
| 515 // they will be running when our object is half torn down. | 523 // they will be running when our object is half torn down. |
| 516 for (ThreadMap::iterator it = threads_.begin(); it != threads_.end(); ++it) | 524 for (ThreadMap::iterator it = threads_.begin(); it != threads_.end(); ++it) |
| 517 it->second->Join(); | 525 it->second->Join(); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 602 | 610 |
| 603 bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread( | 611 bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread( |
| 604 SequenceToken sequence_token) const { | 612 SequenceToken sequence_token) const { |
| 605 AutoLock lock(lock_); | 613 AutoLock lock(lock_); |
| 606 ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId()); | 614 ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId()); |
| 607 if (found == threads_.end()) | 615 if (found == threads_.end()) |
| 608 return false; | 616 return false; |
| 609 return found->second->running_sequence().Equals(sequence_token); | 617 return found->second->running_sequence().Equals(sequence_token); |
| 610 } | 618 } |
| 611 | 619 |
| 612 void SequencedWorkerPool::Inner::FlushForTesting() { | 620 // See https://code.google.com/p/chromium/issues/detail?id=168415 |
| 621 // * executes all pending non-delayed tasks and deletes the associated closures | |
| 622 // * skips executing all pending delayed tasks, but does delete their closures | |
| 623 // * accepts new tasks while in the act of cleaning up | |
| 624 void SequencedWorkerPool::Inner::CleanupForTesting() { | |
| 625 DCHECK(!RunsTasksOnCurrentThread()); | |
| 626 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 613 AutoLock lock(lock_); | 627 AutoLock lock(lock_); |
| 614 while (!IsIdle()) | 628 if (shutdown_called_) |
| 615 is_idle_cv_.Wait(); | 629 return; |
| 630 CHECK_EQ(CLEANUP_DONE, cleanup_state_); | |
| 631 if (!thread_being_created_ && threads_.empty()) | |
| 632 return; | |
| 633 cleanup_state_ = CLEANUP_REQUESTED; | |
| 634 cleanup_idlers_ = 0; | |
| 635 has_work_cv_.Signal(); | |
| 636 while (cleanup_state_ != CLEANUP_DONE) | |
| 637 cleanup_cv_.Wait(); | |
| 616 } | 638 } |
| 617 | 639 |
| 618 void SequencedWorkerPool::Inner::SignalHasWorkForTesting() { | 640 void SequencedWorkerPool::Inner::SignalHasWorkForTesting() { |
| 619 SignalHasWork(); | 641 SignalHasWork(); |
| 620 } | 642 } |
| 621 | 643 |
| 622 void SequencedWorkerPool::Inner::Shutdown( | 644 void SequencedWorkerPool::Inner::Shutdown( |
| 623 int max_new_blocking_tasks_after_shutdown) { | 645 int max_new_blocking_tasks_after_shutdown) { |
| 624 DCHECK_GE(max_new_blocking_tasks_after_shutdown, 0); | 646 DCHECK_GE(max_new_blocking_tasks_after_shutdown, 0); |
| 625 { | 647 { |
| 626 AutoLock lock(lock_); | 648 AutoLock lock(lock_); |
| 627 | |
| 628 if (shutdown_called_) | 649 if (shutdown_called_) |
| 629 return; | 650 return; |
| 651 CHECK_EQ(CLEANUP_DONE, cleanup_state_); | |
| 630 shutdown_called_ = true; | 652 shutdown_called_ = true; |
| 631 max_blocking_tasks_after_shutdown_ = max_new_blocking_tasks_after_shutdown; | 653 max_blocking_tasks_after_shutdown_ = max_new_blocking_tasks_after_shutdown; |
| 632 | 654 |
| 633 // Tickle the threads. This will wake up a waiting one so it will know that | 655 // 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. | 656 // it can exit, which in turn will wake up any other waiting ones. |
| 635 SignalHasWork(); | 657 SignalHasWork(); |
| 636 | 658 |
| 637 // There are no pending or running tasks blocking shutdown, we're done. | 659 // There are no pending or running tasks blocking shutdown, we're done. |
| 638 if (CanShutdown()) | 660 if (CanShutdown()) |
| 639 return; | 661 return; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 665 std::pair<ThreadMap::iterator, bool> result = | 687 std::pair<ThreadMap::iterator, bool> result = |
| 666 threads_.insert( | 688 threads_.insert( |
| 667 std::make_pair(this_worker->tid(), make_linked_ptr(this_worker))); | 689 std::make_pair(this_worker->tid(), make_linked_ptr(this_worker))); |
| 668 DCHECK(result.second); | 690 DCHECK(result.second); |
| 669 | 691 |
| 670 while (true) { | 692 while (true) { |
| 671 #if defined(OS_MACOSX) | 693 #if defined(OS_MACOSX) |
| 672 base::mac::ScopedNSAutoreleasePool autorelease_pool; | 694 base::mac::ScopedNSAutoreleasePool autorelease_pool; |
| 673 #endif | 695 #endif |
| 674 | 696 |
| 697 if (cleanup_state_ != CLEANUP_DONE) | |
| 698 HandleCleanup(); | |
|
jar (doing other things)
2013/01/15 22:59:59
It is surprising we call this in 3 of the 4 states
| |
| 699 | |
| 675 // See GetWork for what delete_these_outside_lock is doing. | 700 // See GetWork for what delete_these_outside_lock is doing. |
| 676 SequencedTask task; | 701 SequencedTask task; |
| 677 TimeDelta wait_time; | 702 TimeDelta wait_time; |
| 678 std::vector<Closure> delete_these_outside_lock; | 703 std::vector<Closure> delete_these_outside_lock; |
| 679 GetWorkStatus status = | 704 GetWorkStatus status = |
| 680 GetWork(&task, &wait_time, &delete_these_outside_lock); | 705 GetWork(&task, &wait_time, &delete_these_outside_lock); |
| 681 if (status == GET_WORK_FOUND) { | 706 if (status == GET_WORK_FOUND) { |
| 682 TRACE_EVENT_FLOW_END0("task", "SequencedWorkerPool::PostTask", | 707 TRACE_EVENT_FLOW_END0("task", "SequencedWorkerPool::PostTask", |
| 683 TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this)))); | 708 TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this)))); |
| 684 TRACE_EVENT2("task", "SequencedWorkerPool::ThreadLoop", | 709 TRACE_EVENT2("task", "SequencedWorkerPool::ThreadLoop", |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 710 start_time, tracked_objects::ThreadData::NowForEndOfRun()); | 735 start_time, tracked_objects::ThreadData::NowForEndOfRun()); |
| 711 | 736 |
| 712 this_worker->set_running_task_info( | 737 this_worker->set_running_task_info( |
| 713 SequenceToken(), CONTINUE_ON_SHUTDOWN); | 738 SequenceToken(), CONTINUE_ON_SHUTDOWN); |
| 714 | 739 |
| 715 // Make sure our task is erased outside the lock for the same reason | 740 // Make sure our task is erased outside the lock for the same reason |
| 716 // we do this with delete_these_oustide_lock. | 741 // we do this with delete_these_oustide_lock. |
| 717 task.task = Closure(); | 742 task.task = Closure(); |
| 718 } | 743 } |
| 719 DidRunWorkerTask(task); // Must be done inside the lock. | 744 DidRunWorkerTask(task); // Must be done inside the lock. |
| 745 } else if (cleanup_state_ == CLEANUP_RUNNING) { | |
| 746 switch (status) { | |
| 747 case GET_WORK_NOT_FOUND: | |
| 748 cleanup_state_ = CLEANUP_DONE; | |
| 749 cleanup_cv_.Broadcast(); | |
| 750 break; | |
| 751 case GET_WORK_WAIT: { | |
| 752 AutoUnlock unlock(lock_); | |
| 753 delete_these_outside_lock.clear(); | |
| 754 } | |
| 755 break; | |
| 756 default: | |
| 757 NOTREACHED(); | |
| 758 } | |
| 720 } else { | 759 } else { |
| 721 // When we're terminating and there's no more work, we can | 760 // When we're terminating and there's no more work, we can |
| 722 // shut down, other workers can complete any pending or new tasks. | 761 // shut down, other workers can complete any pending or new tasks. |
| 723 // We can get additional tasks posted after shutdown_called_ is set | 762 // We can get additional tasks posted after shutdown_called_ is set |
| 724 // but only worker threads are allowed to post tasks at that time, and | 763 // but only worker threads are allowed to post tasks at that time, and |
| 725 // the workers responsible for posting those tasks will be available | 764 // the workers responsible for posting those tasks will be available |
| 726 // to run them. Also, there may be some tasks stuck behind running | 765 // to run them. Also, there may be some tasks stuck behind running |
| 727 // ones with the same sequence token, but additional threads won't | 766 // ones with the same sequence token, but additional threads won't |
| 728 // help this case. | 767 // help this case. |
| 729 if (shutdown_called_ && | 768 if (shutdown_called_ && |
| 730 blocking_shutdown_pending_task_count_ == 0) | 769 blocking_shutdown_pending_task_count_ == 0) |
| 731 break; | 770 break; |
| 732 waiting_thread_count_++; | 771 waiting_thread_count_++; |
| 733 // This is the only time that IsIdle() can go to true. | |
| 734 if (IsIdle()) | |
| 735 is_idle_cv_.Signal(); | |
| 736 | 772 |
| 737 switch (status) { | 773 switch (status) { |
| 738 case GET_WORK_NOT_FOUND: | 774 case GET_WORK_NOT_FOUND: |
| 739 has_work_cv_.Wait(); | 775 has_work_cv_.Wait(); |
| 740 break; | 776 break; |
| 741 case GET_WORK_WAIT: | 777 case GET_WORK_WAIT: |
| 742 has_work_cv_.TimedWait(wait_time); | 778 has_work_cv_.TimedWait(wait_time); |
| 743 break; | 779 break; |
| 744 default: | 780 default: |
| 745 NOTREACHED(); | 781 NOTREACHED(); |
| 746 } | 782 } |
| 747 waiting_thread_count_--; | 783 waiting_thread_count_--; |
| 748 } | 784 } |
| 749 } | 785 } |
| 750 } // Release lock_. | 786 } // Release lock_. |
| 751 | 787 |
| 752 // We noticed we should exit. Wake up the next worker so it knows it should | 788 // We noticed we should exit. Wake up the next worker so it knows it should |
| 753 // exit as well (because the Shutdown() code only signals once). | 789 // exit as well (because the Shutdown() code only signals once). |
| 754 SignalHasWork(); | 790 SignalHasWork(); |
| 755 | 791 |
| 756 // Possibly unblock shutdown. | 792 // Possibly unblock shutdown. |
| 757 can_shutdown_cv_.Signal(); | 793 can_shutdown_cv_.Signal(); |
| 758 } | 794 } |
| 759 | 795 |
| 760 bool SequencedWorkerPool::Inner::IsIdle() const { | 796 void SequencedWorkerPool::Inner::HandleCleanup() { |
| 761 lock_.AssertAcquired(); | 797 lock_.AssertAcquired(); |
| 762 return pending_tasks_.empty() && waiting_thread_count_ == threads_.size(); | 798 if (cleanup_state_ == CLEANUP_REQUESTED) { |
| 799 // We win! We get to do the cleanup as soon as the others wise up and idle. | |
| 800 cleanup_state_ = CLEANUP_WAITING; | |
| 801 while (thread_being_created_ && | |
| 802 cleanup_idlers_ != threads_.size() - 1) { | |
| 803 has_work_cv_.Signal(); | |
| 804 cleanup_cv_.Wait(); | |
| 805 } | |
| 806 cleanup_state_ = CLEANUP_RUNNING; | |
| 807 return; | |
| 808 } | |
| 809 if (cleanup_state_ == CLEANUP_WAITING) { | |
| 810 // Another worker thread is cleaning up, we idle here until thats done. | |
| 811 ++cleanup_idlers_; | |
| 812 cleanup_cv_.Broadcast(); | |
| 813 while (cleanup_state_ != CLEANUP_DONE) | |
| 814 cleanup_cv_.Wait(); | |
| 815 return; | |
| 816 } | |
| 817 DCHECK_EQ(CLEANUP_RUNNING, cleanup_state_); | |
| 763 } | 818 } |
| 764 | 819 |
| 765 int SequencedWorkerPool::Inner::LockedGetNamedTokenID( | 820 int SequencedWorkerPool::Inner::LockedGetNamedTokenID( |
| 766 const std::string& name) { | 821 const std::string& name) { |
| 767 lock_.AssertAcquired(); | 822 lock_.AssertAcquired(); |
| 768 DCHECK(!name.empty()); | 823 DCHECK(!name.empty()); |
| 769 | 824 |
| 770 std::map<std::string, int>::const_iterator found = | 825 std::map<std::string, int>::const_iterator found = |
| 771 named_sequence_tokens_.find(name); | 826 named_sequence_tokens_.find(name); |
| 772 if (found != named_sequence_tokens_.end()) | 827 if (found != named_sequence_tokens_.end()) |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 831 // We assume that the loop below doesn't take too long and so we can just do | 886 // We assume that the loop below doesn't take too long and so we can just do |
| 832 // a single call to TimeTicks::Now(). | 887 // a single call to TimeTicks::Now(). |
| 833 const TimeTicks current_time = TimeTicks::Now(); | 888 const TimeTicks current_time = TimeTicks::Now(); |
| 834 while (i != pending_tasks_.end()) { | 889 while (i != pending_tasks_.end()) { |
| 835 if (!IsSequenceTokenRunnable(i->sequence_token_id)) { | 890 if (!IsSequenceTokenRunnable(i->sequence_token_id)) { |
| 836 unrunnable_tasks++; | 891 unrunnable_tasks++; |
| 837 ++i; | 892 ++i; |
| 838 continue; | 893 continue; |
| 839 } | 894 } |
| 840 | 895 |
| 896 // Let's try running all delayed tasks during cleanup? | |
|
jar (doing other things)
2013/01/15 22:59:59
What's up with the question mark?
...also... I th
| |
| 897 if (cleanup_state_ == CLEANUP_RUNNING) { | |
| 898 *task = *i; | |
| 899 pending_tasks_.erase(i); | |
| 900 if (task->shutdown_behavior == BLOCK_SHUTDOWN) | |
| 901 blocking_shutdown_pending_task_count_--; | |
| 902 status = GET_WORK_FOUND; | |
| 903 break; | |
| 904 } | |
| 905 | |
| 841 if (i->time_to_run > current_time) { | 906 if (i->time_to_run > current_time) { |
| 842 // The time to run has not come yet. | 907 // The time to run has not come yet. |
| 843 *wait_time = i->time_to_run - current_time; | 908 *wait_time = i->time_to_run - current_time; |
| 844 status = GET_WORK_WAIT; | 909 status = GET_WORK_WAIT; |
| 910 /* | |
| 911 if (cleanup_state_ == CLEANUP_RUNNING) { | |
| 912 delete_these_outside_lock->push_back(i->task); | |
| 913 pending_tasks_.erase(i); | |
| 914 } | |
| 915 */ | |
| 845 break; | 916 break; |
| 846 } | 917 } |
| 847 | 918 |
| 848 if (shutdown_called_ && i->shutdown_behavior != BLOCK_SHUTDOWN) { | 919 if (shutdown_called_ && i->shutdown_behavior != BLOCK_SHUTDOWN) { |
| 849 // We're shutting down and the task we just found isn't blocking | 920 // We're shutting down and the task we just found isn't blocking |
| 850 // shutdown. Delete it and get more work. | 921 // shutdown. Delete it and get more work. |
| 851 // | 922 // |
| 852 // Note that we do not want to delete unrunnable tasks. Deleting a task | 923 // Note that we do not want to delete unrunnable tasks. Deleting a task |
| 853 // can have side effects (like freeing some objects) and deleting a | 924 // can have side effects (like freeing some objects) and deleting a |
| 854 // task that's supposed to run after one that's currently running could | 925 // task that's supposed to run after one that's currently running could |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1139 bool SequencedWorkerPool::RunsTasksOnCurrentThread() const { | 1210 bool SequencedWorkerPool::RunsTasksOnCurrentThread() const { |
| 1140 return inner_->RunsTasksOnCurrentThread(); | 1211 return inner_->RunsTasksOnCurrentThread(); |
| 1141 } | 1212 } |
| 1142 | 1213 |
| 1143 bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread( | 1214 bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread( |
| 1144 SequenceToken sequence_token) const { | 1215 SequenceToken sequence_token) const { |
| 1145 return inner_->IsRunningSequenceOnCurrentThread(sequence_token); | 1216 return inner_->IsRunningSequenceOnCurrentThread(sequence_token); |
| 1146 } | 1217 } |
| 1147 | 1218 |
| 1148 void SequencedWorkerPool::FlushForTesting() { | 1219 void SequencedWorkerPool::FlushForTesting() { |
| 1149 inner_->FlushForTesting(); | 1220 inner_->CleanupForTesting(); |
| 1150 } | 1221 } |
| 1151 | 1222 |
| 1152 void SequencedWorkerPool::SignalHasWorkForTesting() { | 1223 void SequencedWorkerPool::SignalHasWorkForTesting() { |
| 1153 inner_->SignalHasWorkForTesting(); | 1224 inner_->SignalHasWorkForTesting(); |
| 1154 } | 1225 } |
| 1155 | 1226 |
| 1156 void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) { | 1227 void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) { |
| 1157 DCHECK(constructor_message_loop_->BelongsToCurrentThread()); | 1228 DCHECK(constructor_message_loop_->BelongsToCurrentThread()); |
| 1158 inner_->Shutdown(max_new_blocking_tasks_after_shutdown); | 1229 inner_->Shutdown(max_new_blocking_tasks_after_shutdown); |
| 1159 } | 1230 } |
| 1160 | 1231 |
| 1161 } // namespace base | 1232 } // namespace base |
| OLD | NEW |