1 // Copyright 2019 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 CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_
6 #define CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_
7 
8 #include <array>
9 
10 #include "base/callback_helpers.h"
11 #include "base/memory/scoped_refptr.h"
12 #include "base/task/sequence_manager/task_queue.h"
13 #include "content/common/content_export.h"
14 #include "content/public/browser/browser_thread.h"
15 
16 namespace base {
17 namespace sequence_manager {
18 class SequenceManager;
19 class TimeDomain;
20 }  // namespace sequence_manager
21 }  // namespace base
22 
23 namespace content {
24 
25 // Common task queues for browser threads. This class holds all the queues
26 // needed by browser threads. This makes it easy for all browser threads to have
27 // the same queues. Thic class also provides a Handler to act on the queues from
28 // any thread.
29 //
30 // Instances must be created and destroyed on the same thread as the
31 // underlying SequenceManager and instances are not allowed to outlive this
32 // SequenceManager. All methods of this class must be called from the
33 // associated thread unless noted otherwise. If you need to perform operations
34 // from a different thread use the a Handle instance instead.
35 //
36 // Attention: All queues are initially disabled, that is, tasks will not be run
37 // for them.
38 class CONTENT_EXPORT BrowserTaskQueues {
39  public:
40   enum class QueueType {
41     // Catch all for tasks that don't fit other categories.
42     // TODO(alexclarke): Introduce new semantic types as needed to minimize the
43     // number of default tasks. Has the same priority as kUserBlocking.
44     kDefault,
45 
46     // For non-urgent work, that will only execute if there's nothing else to
47     // do. Can theoretically be starved indefinitely although that's unlikely in
48     // practice.
49     kBestEffort,
50 
51     // For tasks on the critical path up to issuing the initial navigation.
52     kBootstrap,
53 
54     // For preconnection-related tasks.
55     kPreconnection,
56 
57     // base::TaskPriority::kUserBlocking maps to this task queue. It's for tasks
58     // that affect the UI immediately after a user interaction. Has the same
59     // priority as kDefault.
60     kUserBlocking,
61 
62     // base::TaskPriority::kUserVisible maps to this task queue. The result of
63     // these tasks are visible to the user (in the UI or as a side-effect on the
64     // system) but they are not an immediate response to a user interaction.
65     kUserVisible,
66 
67     kMaxValue = kUserVisible
68   };
69 
70   static constexpr size_t kNumQueueTypes =
71       static_cast<size_t>(QueueType::kMaxValue) + 1;
72 
73   // Handle to a BrowserTaskQueues instance that can be used from any thread
74   // as all operations are thread safe.
75   //
76   // If the underlying BrowserTaskQueues is destroyed all methods of this
77   // class become no-ops, that is it is safe for this class to outlive its
78   // parent BrowserTaskQueues.
79   class CONTENT_EXPORT Handle : public base::RefCountedThreadSafe<Handle> {
80    public:
81     REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
82 
83     // Returns the task runner that should be returned by
84     // ThreadTaskRunnerHandle::Get().
GetDefaultTaskRunner()85     const scoped_refptr<base::SingleThreadTaskRunner>& GetDefaultTaskRunner() {
86       return default_task_runner_;
87     }
88 
GetBrowserTaskRunner(QueueType queue_type)89     const scoped_refptr<base::SingleThreadTaskRunner>& GetBrowserTaskRunner(
90         QueueType queue_type) const {
91       return browser_task_runners_[static_cast<size_t>(queue_type)];
92     }
93 
94     // Initializes any scheduler experiments. Should be called after
95     // FeatureLists have been initialized (which usually happens after task
96     // queues are set up).
97     void PostFeatureListInitializationSetup();
98 
99     // Enables all tasks queues. Can be called multiple times.
100     void EnableAllQueues();
101 
102     // Enables all task queues except the effort ones. Can be called multiple
103     // times.
104     void EnableAllExceptBestEffortQueues();
105 
106     // Schedules |on_pending_task_ran| to run when all pending tasks (at the
107     // time this method was invoked) have run. Only "runnable" tasks are taken
108     // into account, that is tasks from disabled queues are ignored, also this
109     // only works reliably for immediate tasks, delayed tasks might or might not
110     // run depending on timing.
111     //
112     // The callback will run on the thread associated with this Handle, unless
113     // that thread is no longer accepting tasks; in which case it will be run
114     // inline immediately.
115     //
116     // The recommended usage pattern is:
117     // RunLoop run_loop;
118     // handle.ScheduleRunAllPendingTasksForTesting(run_loop.QuitClosure());
119     // run_loop.Run();
120     void ScheduleRunAllPendingTasksForTesting(
121         base::OnceClosure on_pending_task_ran);
122 
123    private:
124     friend base::RefCountedThreadSafe<Handle>;
125 
126     // Only BrowserTaskQueues can create new instances
127     friend class BrowserTaskQueues;
128 
129     ~Handle();
130 
131     explicit Handle(BrowserTaskQueues* task_queues);
132 
133     // |outer_| can only be safely used from a task posted to one of the
134     // runners.
135     BrowserTaskQueues* outer_ = nullptr;
136     scoped_refptr<base::SingleThreadTaskRunner> control_task_runner_;
137     scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
138     std::array<scoped_refptr<base::SingleThreadTaskRunner>, kNumQueueTypes>
139         browser_task_runners_;
140   };
141 
142   // |sequence_manager| and |time_domain| must outlive this instance.
143   explicit BrowserTaskQueues(
144       BrowserThread::ID thread_id,
145       base::sequence_manager::SequenceManager* sequence_manager,
146       base::sequence_manager::TimeDomain* time_domain);
147 
148   // Destroys all queues.
149   ~BrowserTaskQueues();
150 
GetHandle()151   scoped_refptr<Handle> GetHandle() { return handle_; }
152 
153  private:
154   // All these methods can only be called from the associated thread. To make
155   // sure that is the case they will always be called from a task posted to the
156   // |control_queue_|.
157   void StartRunAllPendingTasksForTesting(
158       base::ScopedClosureRunner on_pending_task_ran);
159   void EndRunAllPendingTasksForTesting(
160       base::ScopedClosureRunner on_pending_task_ran);
161   void EnableAllQueues();
162   void EnableAllExceptBestEffortQueues();
163   void PostFeatureListInitializationSetup();
164 
GetBrowserTaskQueue(QueueType type)165   base::sequence_manager::TaskQueue* GetBrowserTaskQueue(QueueType type) const {
166     return queue_data_[static_cast<size_t>(type)].task_queue.get();
167   }
168 
169   std::array<scoped_refptr<base::SingleThreadTaskRunner>, kNumQueueTypes>
170   CreateBrowserTaskRunners() const;
171 
172   struct QueueData {
173     QueueData();
174     ~QueueData();
175     scoped_refptr<base::sequence_manager::TaskQueue> task_queue;
176     std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter> voter;
177   };
178   std::array<QueueData, kNumQueueTypes> queue_data_;
179 
180   // Helper queue to make sure private methods run on the associated thread. the
181   // control queue has maximum priority and will never be disabled.
182   scoped_refptr<base::sequence_manager::TaskQueue> control_queue_;
183 
184   // Queue that backs the default TaskRunner registered with SequenceManager.
185   // This will be the one returned by ThreadTaskRunnerHandle::Get(). Note this
186   // is different from QueueType:kDefault as this queue needs to be enabled from
187   // the beginning.
188   scoped_refptr<base::sequence_manager::TaskQueue> default_task_queue_;
189 
190   // Helper queue to run all pending tasks.
191   scoped_refptr<base::sequence_manager::TaskQueue> run_all_pending_tasks_queue_;
192   int run_all_pending_nesting_level_ = 0;
193 
194   scoped_refptr<Handle> handle_;
195 };
196 
197 }  // namespace content
198 
199 #endif  // CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_
200