1 // Copyright 2016 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 COMPONENTS_OFFLINE_PAGES_TASK_TASK_QUEUE_H_
6 #define COMPONENTS_OFFLINE_PAGES_TASK_TASK_QUEUE_H_
7 
8 #include <memory>
9 
10 #include "base/callback.h"
11 #include "base/containers/queue.h"
12 #include "base/macros.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/sequence_checker.h"
16 #include "components/offline_pages/task/task.h"
17 
18 namespace base {
19 class SingleThreadTaskRunner;
20 }  // namespace base
21 
22 namespace offline_pages {
23 
24 // Class for coordinating |Task|s in relation to access to a specific resource.
25 // As a task, we understand a set of asynchronous operations (possibly switching
26 // threads) that access a set of sensitive resource(s). Because the resource
27 // state is modified and individual steps of a task are asynchronous, allowing
28 // certain tasks to run in parallel may lead to incorrect results. This class
29 // allows for ordering of tasks in a FIFO manner, to ensure two tasks modifying
30 // a resources are not run at the same time.
31 //
32 // Consumers of this class should create an instance of TaskQueue and implement
33 // tasks that need to be run sequentially. New task will only be started when
34 // the previous one calls |Task::TaskComplete|.
35 //
36 // Methods on TaskQueue should be called from the same thread from which it
37 // is created.
38 class TaskQueue {
39  public:
40   class Delegate {
41    public:
~Delegate()42     virtual ~Delegate() {}
43 
44     // Invoked once when TaskQueue reached 0 tasks.
45     virtual void OnTaskQueueIsIdle() = 0;
46   };
47 
48   explicit TaskQueue(Delegate* delegate);
49   ~TaskQueue();
50 
51   // Adds a task to the queue. Queue takes ownership of the task.
52   void AddTask(std::unique_ptr<Task> task);
53   // Whether the task queue has any pending (not-running) tasks.
54   bool HasPendingTasks() const;
55   // Whether there is a task currently running.
56   bool HasRunningTask() const;
57 
58  private:
59   // Checks whether there are any tasks to run, as well as whether no task is
60   // currently running. When both are met, it will start the next task in the
61   // queue.
62   void StartTaskIfAvailable();
63 
64   void RunCurrentTask();
65 
66   // Callback for informing the queue that a task was completed. Can be called
67   // from any thread.
68   static void TaskCompletedCallback(
69       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
70       base::WeakPtr<TaskQueue> task_queue,
71       Task* task);
72 
73   void TaskCompleted(Task* task);
74 
75   void InformTaskQueueIsIdle();
76 
77   // This TaskQueue's task runner, set on construction using the instance
78   // assigned to the current thread.
79   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
80 
81   // Owns and outlives this TaskQueue.
82   Delegate* delegate_;
83 
84   // Currently running tasks.
85   std::unique_ptr<Task> current_task_;
86 
87   // A FIFO queue of tasks that will be run using this task queue.
88   base::queue<std::unique_ptr<Task>> tasks_;
89 
90   SEQUENCE_CHECKER(sequence_checker_);
91 
92   base::WeakPtrFactory<TaskQueue> weak_ptr_factory_{this};
93 
94   DISALLOW_COPY_AND_ASSIGN(TaskQueue);
95 };
96 
97 }  // namespace offline_pages
98 
99 #endif  // COMPONENTS_OFFLINE_PAGES_TASK_TASK_QUEUE_H_
100