| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #ifndef CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | |
| 6 #define CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | |
| 7 | |
| 8 #include <map> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/memory/ref_counted.h" | |
| 13 #include "base/synchronization/condition_variable.h" | |
| 14 #include "cc/base/cc_export.h" | |
| 15 | |
| 16 namespace cc { | |
| 17 | |
| 18 class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> { | |
| 19 public: | |
| 20 typedef std::vector<scoped_refptr<Task>> Vector; | |
| 21 | |
| 22 virtual void RunOnWorkerThread() = 0; | |
| 23 | |
| 24 void WillRun(); | |
| 25 void DidRun(); | |
| 26 bool HasFinishedRunning() const; | |
| 27 | |
| 28 protected: | |
| 29 friend class base::RefCountedThreadSafe<Task>; | |
| 30 | |
| 31 Task(); | |
| 32 virtual ~Task(); | |
| 33 | |
| 34 bool will_run_; | |
| 35 bool did_run_; | |
| 36 }; | |
| 37 | |
| 38 // Dependencies are represented as edges in a task graph. Each graph node is | |
| 39 // assigned a priority and a run count that matches the number of dependencies. | |
| 40 // Priority range from 0 (most favorable scheduling) to UINT_MAX (least | |
| 41 // favorable). | |
| 42 struct CC_EXPORT TaskGraph { | |
| 43 struct Node { | |
| 44 class TaskComparator { | |
| 45 public: | |
| 46 explicit TaskComparator(const Task* task) : task_(task) {} | |
| 47 | |
| 48 bool operator()(const Node& node) const { return node.task == task_; } | |
| 49 | |
| 50 private: | |
| 51 const Task* task_; | |
| 52 }; | |
| 53 | |
| 54 typedef std::vector<Node> Vector; | |
| 55 | |
| 56 Node(Task* task, unsigned priority, size_t dependencies) | |
| 57 : task(task), priority(priority), dependencies(dependencies) {} | |
| 58 | |
| 59 Task* task; | |
| 60 unsigned priority; | |
| 61 size_t dependencies; | |
| 62 }; | |
| 63 | |
| 64 struct Edge { | |
| 65 typedef std::vector<Edge> Vector; | |
| 66 | |
| 67 Edge(const Task* task, Task* dependent) | |
| 68 : task(task), dependent(dependent) {} | |
| 69 | |
| 70 const Task* task; | |
| 71 Task* dependent; | |
| 72 }; | |
| 73 | |
| 74 TaskGraph(); | |
| 75 ~TaskGraph(); | |
| 76 | |
| 77 void Swap(TaskGraph* other); | |
| 78 void Reset(); | |
| 79 | |
| 80 Node::Vector nodes; | |
| 81 Edge::Vector edges; | |
| 82 }; | |
| 83 | |
| 84 class TaskGraphRunner; | |
| 85 | |
| 86 // Opaque identifier that defines a namespace of tasks. | |
| 87 class CC_EXPORT NamespaceToken { | |
| 88 public: | |
| 89 NamespaceToken() : id_(0) {} | |
| 90 ~NamespaceToken() {} | |
| 91 | |
| 92 bool IsValid() const { return id_ != 0; } | |
| 93 | |
| 94 private: | |
| 95 friend class TaskGraphRunner; | |
| 96 | |
| 97 explicit NamespaceToken(int id) : id_(id) {} | |
| 98 | |
| 99 int id_; | |
| 100 }; | |
| 101 | |
| 102 // A TaskGraphRunner is used to process tasks with dependencies. There can | |
| 103 // be any number of TaskGraphRunner instances per thread. Tasks can be scheduled | |
| 104 // from any thread and they can be run on any thread. | |
| 105 class CC_EXPORT TaskGraphRunner { | |
| 106 public: | |
| 107 TaskGraphRunner(); | |
| 108 virtual ~TaskGraphRunner(); | |
| 109 | |
| 110 // Returns a unique token that can be used to pass a task graph to | |
| 111 // ScheduleTasks(). Valid tokens are always nonzero. | |
| 112 NamespaceToken GetNamespaceToken(); | |
| 113 | |
| 114 // Schedule running of tasks in |graph|. Tasks previously scheduled but no | |
| 115 // longer needed will be canceled unless already running. Canceled tasks are | |
| 116 // moved to |completed_tasks| without being run. The result is that once | |
| 117 // scheduled, a task is guaranteed to end up in the |completed_tasks| queue | |
| 118 // even if it later gets canceled by another call to ScheduleTasks(). | |
| 119 void ScheduleTasks(NamespaceToken token, TaskGraph* graph); | |
| 120 | |
| 121 // Wait for all scheduled tasks to finish running. | |
| 122 void WaitForTasksToFinishRunning(NamespaceToken token); | |
| 123 | |
| 124 // Collect all completed tasks in |completed_tasks|. | |
| 125 void CollectCompletedTasks(NamespaceToken token, | |
| 126 Task::Vector* completed_tasks); | |
| 127 | |
| 128 // Run tasks until Shutdown() is called. | |
| 129 void Run(); | |
| 130 | |
| 131 // Process all pending tasks, but don't wait/sleep. Return as soon as all | |
| 132 // tasks that can be run are taken care of. | |
| 133 void RunUntilIdle(); | |
| 134 | |
| 135 // Signals the Run method to return when it becomes idle. It will continue to | |
| 136 // process tasks and future tasks as long as they are scheduled. | |
| 137 // Warning: if the TaskGraphRunner remains busy, it may never quit. | |
| 138 void Shutdown(); | |
| 139 | |
| 140 private: | |
| 141 struct PrioritizedTask { | |
| 142 typedef std::vector<PrioritizedTask> Vector; | |
| 143 | |
| 144 PrioritizedTask(Task* task, unsigned priority) | |
| 145 : task(task), priority(priority) {} | |
| 146 | |
| 147 Task* task; | |
| 148 unsigned priority; | |
| 149 }; | |
| 150 | |
| 151 typedef std::vector<const Task*> TaskVector; | |
| 152 | |
| 153 struct TaskNamespace { | |
| 154 typedef std::vector<TaskNamespace*> Vector; | |
| 155 | |
| 156 TaskNamespace(); | |
| 157 ~TaskNamespace(); | |
| 158 | |
| 159 // Current task graph. | |
| 160 TaskGraph graph; | |
| 161 | |
| 162 // Ordered set of tasks that are ready to run. | |
| 163 PrioritizedTask::Vector ready_to_run_tasks; | |
| 164 | |
| 165 // Completed tasks not yet collected by origin thread. | |
| 166 Task::Vector completed_tasks; | |
| 167 | |
| 168 // This set contains all currently running tasks. | |
| 169 TaskVector running_tasks; | |
| 170 }; | |
| 171 | |
| 172 typedef std::map<int, TaskNamespace> TaskNamespaceMap; | |
| 173 | |
| 174 static bool CompareTaskPriority(const PrioritizedTask& a, | |
| 175 const PrioritizedTask& b) { | |
| 176 // In this system, numerically lower priority is run first. | |
| 177 return a.priority > b.priority; | |
| 178 } | |
| 179 | |
| 180 static bool CompareTaskNamespacePriority(const TaskNamespace* a, | |
| 181 const TaskNamespace* b) { | |
| 182 DCHECK(!a->ready_to_run_tasks.empty()); | |
| 183 DCHECK(!b->ready_to_run_tasks.empty()); | |
| 184 | |
| 185 // Compare based on task priority of the ready_to_run_tasks heap .front() | |
| 186 // will hold the max element of the heap, except after pop_heap, when max | |
| 187 // element is moved to .back(). | |
| 188 return CompareTaskPriority(a->ready_to_run_tasks.front(), | |
| 189 b->ready_to_run_tasks.front()); | |
| 190 } | |
| 191 | |
| 192 static bool HasFinishedRunningTasksInNamespace( | |
| 193 const TaskNamespace* task_namespace) { | |
| 194 return task_namespace->running_tasks.empty() && | |
| 195 task_namespace->ready_to_run_tasks.empty(); | |
| 196 } | |
| 197 | |
| 198 // Run next task. Caller must acquire |lock_| prior to calling this function | |
| 199 // and make sure at least one task is ready to run. | |
| 200 void RunTaskWithLockAcquired(); | |
| 201 | |
| 202 // This lock protects all members of this class. Do not read or modify | |
| 203 // anything without holding this lock. Do not block while holding this lock. | |
| 204 mutable base::Lock lock_; | |
| 205 | |
| 206 // Condition variable that is waited on by Run() until new tasks are ready to | |
| 207 // run or shutdown starts. | |
| 208 base::ConditionVariable has_ready_to_run_tasks_cv_; | |
| 209 | |
| 210 // Condition variable that is waited on by origin threads until a namespace | |
| 211 // has finished running all associated tasks. | |
| 212 base::ConditionVariable has_namespaces_with_finished_running_tasks_cv_; | |
| 213 | |
| 214 // Provides a unique id to each NamespaceToken. | |
| 215 int next_namespace_id_; | |
| 216 | |
| 217 // This set contains all namespaces with pending, running or completed tasks | |
| 218 // not yet collected. | |
| 219 TaskNamespaceMap namespaces_; | |
| 220 | |
| 221 // Ordered set of task namespaces that have ready to run tasks. | |
| 222 TaskNamespace::Vector ready_to_run_namespaces_; | |
| 223 | |
| 224 // Set during shutdown. Tells Run() to return when no more tasks are pending. | |
| 225 bool shutdown_; | |
| 226 | |
| 227 DISALLOW_COPY_AND_ASSIGN(TaskGraphRunner); | |
| 228 }; | |
| 229 | |
| 230 } // namespace cc | |
| 231 | |
| 232 #endif // CC_RESOURCES_TASK_GRAPH_RUNNER_H_ | |
| OLD | NEW |