Chromium Code Reviews| Index: base/task_scheduler/task_tracker.cc |
| diff --git a/base/task_scheduler/task_tracker.cc b/base/task_scheduler/task_tracker.cc |
| index ea5397049de7b1b350fbb7f9fd41841865a63d83..3f8bed388b7f2d3e1cac3d7a62242bdbcf72a498 100644 |
| --- a/base/task_scheduler/task_tracker.cc |
| +++ b/base/task_scheduler/task_tracker.cc |
| @@ -6,12 +6,12 @@ |
| #include <limits> |
| -#include "base/atomicops.h" |
| #include "base/callback.h" |
| #include "base/debug/task_annotator.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/sequence_token.h" |
| +#include "base/synchronization/condition_variable.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| @@ -128,10 +128,108 @@ class TaskTracker::State { |
| DISALLOW_COPY_AND_ASSIGN(State); |
| }; |
| -TaskTracker::TaskTracker() : state_(new State) {} |
| +TaskTracker::TaskTracker() |
| + : state_(new State), |
| + flush_for_testing_cv_(flush_for_testing_lock_.CreateConditionVariable()), |
| + shutdown_lock_(&flush_for_testing_lock_) {} |
| TaskTracker::~TaskTracker() = default; |
| void TaskTracker::Shutdown() { |
| + ShutdownInternal(); |
| + DCHECK(IsShutdownComplete()); |
| + |
| + // Unblock FlushForTesting() when shutdown completes. |
| + AutoSchedulerLock auto_lock(flush_for_testing_lock_); |
| + flush_for_testing_cv_->Signal(); |
| +} |
| + |
| +void TaskTracker::FlushForTesting() { |
| + AutoSchedulerLock auto_lock(flush_for_testing_lock_); |
| + while (subtle::NoBarrier_Load(&num_pending_undelayed_tasks_) != 0 && |
| + !IsShutdownComplete()) { |
| + flush_for_testing_cv_->Wait(); |
| + } |
| +} |
| + |
| +bool TaskTracker::WillPostTask(const Task* task) { |
| + DCHECK(task); |
| + |
| + if (!BeforePostTask(task->traits.shutdown_behavior())) |
| + return false; |
| + |
| + if (task->delayed_run_time.is_null()) |
| + subtle::NoBarrier_AtomicIncrement(&num_pending_undelayed_tasks_, 1); |
|
gab
2016/09/23 15:39:18
Suggest adding
CQ_INCLUDE_TRYBOTS=master.tryserve
fdoray
2016/09/23 15:56:50
Done.
|
| + |
| + debug::TaskAnnotator task_annotator; |
| + task_annotator.DidQueueTask(kQueueFunctionName, *task); |
| + |
| + return true; |
| +} |
| + |
| +bool TaskTracker::RunTask(const Task* task, |
| + const SequenceToken& sequence_token) { |
| + DCHECK(task); |
| + DCHECK(sequence_token.IsValid()); |
| + |
| + const TaskShutdownBehavior shutdown_behavior = |
| + task->traits.shutdown_behavior(); |
| + const bool can_run_task = BeforeRunTask(shutdown_behavior); |
| + |
| + if (can_run_task) { |
| + // All tasks run through here and the scheduler itself doesn't use |
| + // singletons. Therefore, it isn't necessary to reset the singleton allowed |
| + // bit after running the task. |
| + ThreadRestrictions::SetSingletonAllowed( |
| + task->traits.shutdown_behavior() != |
| + TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN); |
| + |
| + { |
| + // Set up SequenceToken as expected for the scope of the task. |
| + ScopedSetSequenceTokenForCurrentThread |
| + scoped_set_sequence_token_for_current_thread(sequence_token); |
| + |
| + // Set up TaskRunnerHandle as expected for the scope of the task. |
| + std::unique_ptr<SequencedTaskRunnerHandle> sequenced_task_runner_handle; |
| + std::unique_ptr<ThreadTaskRunnerHandle> single_thread_task_runner_handle; |
| + DCHECK(!task->sequenced_task_runner_ref || |
| + !task->single_thread_task_runner_ref); |
| + if (task->sequenced_task_runner_ref) { |
| + sequenced_task_runner_handle.reset( |
| + new SequencedTaskRunnerHandle(task->sequenced_task_runner_ref)); |
| + } else if (task->single_thread_task_runner_ref) { |
| + single_thread_task_runner_handle.reset( |
| + new ThreadTaskRunnerHandle(task->single_thread_task_runner_ref)); |
| + } |
| + |
| + TRACE_TASK_EXECUTION(kRunFunctionName, *task); |
| + |
| + debug::TaskAnnotator task_annotator; |
| + task_annotator.RunTask(kQueueFunctionName, *task); |
| + } |
| + |
| + AfterRunTask(shutdown_behavior); |
| + } |
| + |
| + if (task->delayed_run_time.is_null()) |
| + DecrementNumPendingUndelayedTasks(); |
| + |
| + return can_run_task; |
|
gab
2016/09/23 15:39:18
Does changing the return value of RunTask belong i
fdoray
2016/09/23 15:56:50
I changed this to have a single exit point in RunT
gab
2016/09/23 17:05:25
Ah makes sense, had missed the removal of the retu
|
| +} |
| + |
| +bool TaskTracker::HasShutdownStarted() const { |
| + return state_->HasShutdownStarted(); |
| +} |
| + |
| +bool TaskTracker::IsShutdownComplete() const { |
| + AutoSchedulerLock auto_lock(shutdown_lock_); |
| + return shutdown_event_ && shutdown_event_->IsSignaled(); |
| +} |
| + |
| +void TaskTracker::SetHasShutdownStartedForTesting() { |
| + state_->StartShutdown(); |
| +} |
| + |
| +void TaskTracker::ShutdownInternal() { |
| { |
| AutoSchedulerLock auto_lock(shutdown_lock_); |
| @@ -182,77 +280,6 @@ void TaskTracker::Shutdown() { |
| } |
| } |
| -bool TaskTracker::WillPostTask(const Task* task) { |
| - DCHECK(task); |
| - |
| - if (!BeforePostTask(task->traits.shutdown_behavior())) |
| - return false; |
| - |
| - debug::TaskAnnotator task_annotator; |
| - task_annotator.DidQueueTask(kQueueFunctionName, *task); |
| - |
| - return true; |
| -} |
| - |
| -bool TaskTracker::RunTask(const Task* task, |
| - const SequenceToken& sequence_token) { |
| - DCHECK(task); |
| - DCHECK(sequence_token.IsValid()); |
| - |
| - const TaskShutdownBehavior shutdown_behavior = |
| - task->traits.shutdown_behavior(); |
| - if (!BeforeRunTask(shutdown_behavior)) |
| - return false; |
| - |
| - // All tasks run through here and the scheduler itself doesn't use singletons. |
| - // Therefore, it isn't necessary to reset the singleton allowed bit after |
| - // running the task. |
| - ThreadRestrictions::SetSingletonAllowed( |
| - task->traits.shutdown_behavior() != |
| - TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN); |
| - |
| - { |
| - // Set up SequenceToken as expected for the scope of the task. |
| - ScopedSetSequenceTokenForCurrentThread |
| - scoped_set_sequence_token_for_current_thread(sequence_token); |
| - |
| - // Set up TaskRunnerHandle as expected for the scope of the task. |
| - std::unique_ptr<SequencedTaskRunnerHandle> sequenced_task_runner_handle; |
| - std::unique_ptr<ThreadTaskRunnerHandle> single_thread_task_runner_handle; |
| - DCHECK(!task->sequenced_task_runner_ref || |
| - !task->single_thread_task_runner_ref); |
| - if (task->sequenced_task_runner_ref) { |
| - sequenced_task_runner_handle.reset( |
| - new SequencedTaskRunnerHandle(task->sequenced_task_runner_ref)); |
| - } else if (task->single_thread_task_runner_ref) { |
| - single_thread_task_runner_handle.reset( |
| - new ThreadTaskRunnerHandle(task->single_thread_task_runner_ref)); |
| - } |
| - |
| - TRACE_TASK_EXECUTION(kRunFunctionName, *task); |
| - |
| - debug::TaskAnnotator task_annotator; |
| - task_annotator.RunTask(kQueueFunctionName, *task); |
| - } |
| - |
| - AfterRunTask(shutdown_behavior); |
| - |
| - return true; |
| -} |
| - |
| -bool TaskTracker::HasShutdownStarted() const { |
| - return state_->HasShutdownStarted(); |
| -} |
| - |
| -bool TaskTracker::IsShutdownComplete() const { |
| - AutoSchedulerLock auto_lock(shutdown_lock_); |
| - return shutdown_event_ && shutdown_event_->IsSignaled(); |
| -} |
| - |
| -void TaskTracker::SetHasShutdownStartedForTesting() { |
| - state_->StartShutdown(); |
| -} |
| - |
| bool TaskTracker::BeforePostTask(TaskShutdownBehavior shutdown_behavior) { |
| if (shutdown_behavior == TaskShutdownBehavior::BLOCK_SHUTDOWN) { |
| // BLOCK_SHUTDOWN tasks block shutdown between the moment they are posted |
| @@ -352,5 +379,15 @@ void TaskTracker::OnBlockingShutdownTasksComplete() { |
| shutdown_event_->Signal(); |
| } |
| +void TaskTracker::DecrementNumPendingUndelayedTasks() { |
| + const auto new_num_pending_undelayed_tasks = |
| + subtle::NoBarrier_AtomicIncrement(&num_pending_undelayed_tasks_, -1); |
| + DCHECK_GE(new_num_pending_undelayed_tasks, 0); |
| + if (new_num_pending_undelayed_tasks == 0) { |
| + AutoSchedulerLock auto_lock(flush_for_testing_lock_); |
| + flush_for_testing_cv_->Signal(); |
| + } |
| +} |
| + |
| } // namespace internal |
| } // namespace base |