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
16namespace cc {
17
18class 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).
42struct 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
84class TaskGraphRunner;
85
86// Opaque identifier that defines a namespace of tasks.
87class 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.
105class 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_
233