Chromium Code Reviews| Index: cc/raster/single_thread_task_graph_runner.cc |
| diff --git a/cc/raster/single_thread_task_graph_runner.cc b/cc/raster/single_thread_task_graph_runner.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ce6e76c61e9c180e4ea09f52d60a443c1bed0622 |
| --- /dev/null |
| +++ b/cc/raster/single_thread_task_graph_runner.cc |
| @@ -0,0 +1,149 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "cc/raster/single_thread_task_graph_runner.h" |
| + |
| +#include <string> |
| + |
| +#include "base/threading/simple_thread.h" |
| +#include "base/threading/thread_restrictions.h" |
| +#include "base/trace_event/trace_event.h" |
| + |
| +namespace cc { |
| + |
| +SingleThreadTaskGraphRunner::SingleThreadTaskGraphRunner() |
| + : lock_(), |
| + has_ready_to_run_tasks_cv_(&lock_), |
| + has_namespaces_with_finished_running_tasks_cv_(&lock_), |
| + shutdown_(false) {} |
| + |
| +SingleThreadTaskGraphRunner::~SingleThreadTaskGraphRunner() {} |
| + |
| +void SingleThreadTaskGraphRunner::Start(const std::string& thread_name) { |
| + raster_thread_.reset(new base::DelegateSimpleThread(this, thread_name)); |
| + raster_thread_->Start(); |
| +} |
| + |
| +void SingleThreadTaskGraphRunner::Shutdown() { |
| + // Shutdown raster threads. |
|
reveman
2015/11/19 16:05:46
nit: "Shutdown threads" or maybe just remove this
ericrk
2015/11/23 18:43:37
Done.
|
| + { |
| + base::AutoLock lock(lock_); |
| + |
| + DCHECK(!work_queue_.HasReadyToRunTasks()); |
| + |
| + DCHECK(!shutdown_); |
| + shutdown_ = true; |
| + |
| + // Wake up the worker so it knows it should exit. |
| + has_ready_to_run_tasks_cv_.Signal(); |
| + } |
| + raster_thread_->Join(); |
| +} |
| + |
| +void SingleThreadTaskGraphRunner::ScheduleTasks(NamespaceToken token, |
| + TaskGraph* graph) { |
| + TRACE_EVENT2("cc", "SingleThreadTaskGraphRunner::ScheduleTasks", "num_nodes", |
| + graph->nodes.size(), "num_edges", graph->edges.size()); |
| + |
| + DCHECK(token.IsValid()); |
| + DCHECK(!DependencyMismatch(graph)); |
| + |
| + { |
| + base::AutoLock lock(lock_); |
| + |
| + DCHECK(!shutdown_); |
| + |
| + work_queue_.ScheduleTasks(token, graph); |
| + |
| + // If there is more work available, wake up the worker thread. |
| + if (work_queue_.HasReadyToRunTasks()) |
| + has_ready_to_run_tasks_cv_.Signal(); |
| + } |
| +} |
| + |
| +void SingleThreadTaskGraphRunner::WaitForTasksToFinishRunning( |
| + NamespaceToken token) { |
| + TRACE_EVENT0("cc", |
| + "SingleThreadTaskGraphRunner::WaitForTasksToFinishRunning"); |
| + |
| + DCHECK(token.IsValid()); |
| + |
| + { |
| + base::AutoLock lock(lock_); |
| + base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| + |
| + auto* task_namespace = work_queue_.GetNamespaceForToken(token); |
| + |
| + if (!task_namespace) |
| + return; |
| + |
| + while (!work_queue_.HasFinishedRunningTasksInNamespace(task_namespace)) |
| + has_namespaces_with_finished_running_tasks_cv_.Wait(); |
| + |
| + // There may be other namespaces that have finished running tasks, so wake |
| + // up another origin thread. |
| + has_namespaces_with_finished_running_tasks_cv_.Signal(); |
| + } |
| +} |
| + |
| +void SingleThreadTaskGraphRunner::CollectCompletedTasks( |
| + NamespaceToken token, |
| + Task::Vector* completed_tasks) { |
| + TRACE_EVENT0("cc", "SingleThreadTaskGraphRunner::CollectCompletedTasks"); |
| + |
| + DCHECK(token.IsValid()); |
| + |
| + { |
| + base::AutoLock lock(lock_); |
| + work_queue_.CollectCompletedTasks(token, completed_tasks); |
| + } |
| +} |
| + |
| +void SingleThreadTaskGraphRunner::Run() { |
| + base::AutoLock lock(lock_); |
| + |
| + while (true) { |
| + if (!work_queue_.HasReadyToRunTasks()) { |
| + // Exit when shutdown is set and no more tasks are pending. |
| + if (shutdown_) |
| + break; |
| + |
| + // Wait for more tasks. |
| + has_ready_to_run_tasks_cv_.Wait(); |
| + continue; |
| + } |
| + |
| + RunTaskWithLockAcquired(); |
| + } |
| +} |
| + |
| +void SingleThreadTaskGraphRunner::RunTaskWithLockAcquired() { |
| + TRACE_EVENT0("toplevel", |
| + "SingleThreadTaskGraphRunner::RunTaskWithLockAcquired"); |
| + |
| + lock_.AssertAcquired(); |
| + |
| + auto prioritized_task = work_queue_.GetNextTaskToRun(); |
| + Task* task = prioritized_task.task; |
| + |
| + // Call WillRun() before releasing |lock_| and running task. |
| + task->WillRun(); |
| + |
| + { |
| + base::AutoUnlock unlock(lock_); |
| + task->RunOnWorkerThread(); |
| + } |
| + |
| + // This will mark task as finished running. |
| + task->DidRun(); |
| + |
| + work_queue_.CompleteTask(prioritized_task); |
| + |
| + // If namespace has finished running all tasks, wake up origin thread. |
| + if (work_queue_.HasFinishedRunningTasksInNamespace( |
| + prioritized_task.task_namespace)) |
| + has_namespaces_with_finished_running_tasks_cv_.Signal(); |
| +} |
| + |
| +} // namespace cc |