Home | History | Annotate | Download | only in resources
      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_
    233