1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CC_RESOURCES_TASK_GRAPH_RUNNER_H_
6 #define CC_RESOURCES_TASK_GRAPH_RUNNER_H_
12 #include "base/memory/ref_counted.h"
13 #include "base/synchronization/condition_variable.h"
14 #include "base/threading/simple_thread.h"
15 #include "cc/base/cc_export.h"
16 #include "cc/base/scoped_ptr_deque.h"
21 class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> {
23 typedef std::vector<scoped_refptr<Task> > Vector;
25 virtual void RunOnWorkerThread(unsigned thread_index) = 0;
29 bool HasFinishedRunning() const;
32 friend class base::RefCountedThreadSafe<Task>;
40 // Dependencies are represented as edges in a task graph. Each graph node
41 // is assigned a priority and a run count that matches the number of
43 struct CC_EXPORT TaskGraph {
45 class TaskComparator {
47 explicit TaskComparator(const Task* task) : task_(task) {}
49 bool operator()(const Node& node) const { return node.task == task_; }
55 typedef std::vector<Node> Vector;
57 Node(Task* task, unsigned priority, size_t dependencies)
58 : task(task), priority(priority), dependencies(dependencies) {}
66 typedef std::vector<Edge> Vector;
68 Edge(const Task* task, Task* dependent)
69 : task(task), dependent(dependent) {}
78 void Swap(TaskGraph* other);
85 class TaskGraphRunner;
87 // Opaque identifier that defines a namespace of tasks.
88 class CC_EXPORT NamespaceToken {
90 NamespaceToken() : id_(0) {}
93 bool IsValid() const { return id_ != 0; }
96 friend class TaskGraphRunner;
98 explicit NamespaceToken(int id) : id_(id) {}
103 // A worker thread pool that runs tasks provided by task graph. Destructor
104 // might block and should not be used on a thread that needs to be responsive.
105 class CC_EXPORT TaskGraphRunner : public base::DelegateSimpleThread::Delegate {
107 TaskGraphRunner(size_t num_threads, const std::string& thread_name_prefix);
108 virtual ~TaskGraphRunner();
110 // Returns a unique token that can be used to pass a task graph to
111 // SetTaskGraph(). Valid tokens are always nonzero.
112 NamespaceToken GetNamespaceToken();
114 // Schedule running of tasks in |graph|. Tasks previously scheduled but
115 // no longer needed will be canceled unless already running. Canceled
116 // tasks are moved to |completed_tasks| without being run. The result
117 // is that once scheduled, a task is guaranteed to end up in the
118 // |completed_tasks| queue even if it later gets canceled by another
119 // call to SetTaskGraph().
120 void SetTaskGraph(NamespaceToken token, TaskGraph* graph);
122 // Wait for all scheduled tasks to finish running.
123 void WaitForTasksToFinishRunning(NamespaceToken token);
125 // Collect all completed tasks in |completed_tasks|.
126 void CollectCompletedTasks(NamespaceToken token,
127 Task::Vector* completed_tasks);
129 // Run one task on current thread. Returns false if no tasks are ready
130 // to run. This should only be used by tests.
131 bool RunTaskForTesting();
134 struct PrioritizedTask {
135 typedef std::vector<PrioritizedTask> Vector;
137 PrioritizedTask(Task* task, unsigned priority)
138 : task(task), priority(priority) {}
144 struct TaskNamespace {
145 typedef std::vector<TaskNamespace*> Vector;
150 // Current task graph.
153 // Ordered set of tasks that are ready to run.
154 PrioritizedTask::Vector ready_to_run_tasks;
156 // Completed tasks not yet collected by origin thread.
157 Task::Vector completed_tasks;
159 // Number of currently running tasks.
160 size_t num_running_tasks;
163 typedef std::map<int, TaskNamespace> TaskNamespaceMap;
165 static bool CompareTaskPriority(const PrioritizedTask& a,
166 const PrioritizedTask& b) {
167 // In this system, numerically lower priority is run first.
168 return a.priority > b.priority;
171 static bool CompareTaskNamespacePriority(const TaskNamespace* a,
172 const TaskNamespace* b) {
173 DCHECK(!a->ready_to_run_tasks.empty());
174 DCHECK(!b->ready_to_run_tasks.empty());
176 // Compare based on task priority of the ready_to_run_tasks heap
177 // .front() will hold the max element of the heap,
178 // except after pop_heap, when max element is moved to .back().
179 return CompareTaskPriority(a->ready_to_run_tasks.front(),
180 b->ready_to_run_tasks.front());
183 static bool HasFinishedRunningTasksInNamespace(
184 const TaskNamespace* task_namespace) {
185 return !task_namespace->num_running_tasks &&
186 task_namespace->ready_to_run_tasks.empty();
189 // Overridden from base::DelegateSimpleThread:
190 virtual void Run() OVERRIDE;
192 // Run next task. Caller must acquire |lock_| prior to calling this
193 // function and make sure at least one task is ready to run.
194 void RunTaskWithLockAcquired(int thread_index);
196 // This lock protects all members of this class. Do not read or modify
197 // anything without holding this lock. Do not block while holding this
199 mutable base::Lock lock_;
201 // Condition variable that is waited on by worker threads until new
202 // tasks are ready to run or shutdown starts.
203 base::ConditionVariable has_ready_to_run_tasks_cv_;
205 // Condition variable that is waited on by origin threads until a
206 // namespace has finished running all associated tasks.
207 base::ConditionVariable has_namespaces_with_finished_running_tasks_cv_;
209 // Provides a unique id to each NamespaceToken.
210 int next_namespace_id_;
212 // This set contains all namespaces with pending, running or completed
213 // tasks not yet collected.
214 TaskNamespaceMap namespaces_;
216 // Ordered set of task namespaces that have ready to run tasks.
217 TaskNamespace::Vector ready_to_run_namespaces_;
219 // Provides each running thread loop with a unique index. First thread
221 unsigned next_thread_index_;
223 // This set contains all currently running tasks.
224 typedef std::vector<const Task*> TaskVector;
225 TaskVector running_tasks_;
227 // Set during shutdown. Tells workers to exit when no more tasks
231 ScopedPtrDeque<base::DelegateSimpleThread> workers_;
233 DISALLOW_COPY_AND_ASSIGN(TaskGraphRunner);
236 } // namespace internal
239 #endif // CC_RESOURCES_TASK_GRAPH_RUNNER_H_