blob: c91e31f298f260d21590ca2cff24512b2ad23e9d [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2019 The Chromium Authors
Carlos Caballero5f6212b2019-05-13 13:45:162// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/scheduler/browser_task_queues.h"
6
7#include <iterator>
8
Minoru Chikamunea0317562022-03-22 15:30:219#include "base/check.h"
Carlos Caballero5f6212b2019-05-13 13:45:1610#include "base/feature_list.h"
Avi Drissmanadac21992023-01-11 23:46:3911#include "base/functional/bind.h"
12#include "base/functional/callback_helpers.h"
Carlos Caballero5f6212b2019-05-13 13:45:1613#include "base/memory/scoped_refptr.h"
Carlos Caballero5f6212b2019-05-13 13:45:1614#include "base/task/sequence_manager/sequence_manager.h"
Patrick Monette643cdf62021-10-15 19:13:4215#include "base/task/sequenced_task_runner.h"
Sean Mahere672a662023-01-09 21:42:2816#include "base/task/single_thread_task_runner.h"
Scott Haseley72d89b02023-02-17 03:29:2517#include "content/browser/scheduler/browser_task_priority.h"
Carlos Caballero5f6212b2019-05-13 13:45:1618#include "content/public/browser/browser_thread.h"
19#include "content/public/common/content_features.h"
20
21namespace content {
22namespace {
Carlos Caballero72e8a202019-05-21 16:51:1723
Scott Haseley72d89b02023-02-17 03:29:2524using BrowserTaskPriority = ::content::internal::BrowserTaskPriority;
Aman Verma566a5d22022-09-22 16:30:4825using QueueName = ::perfetto::protos::pbzero::SequenceManagerTask::QueueName;
Carlos Caballero72e8a202019-05-21 16:51:1726using InsertFencePosition =
27 ::base::sequence_manager::TaskQueue::InsertFencePosition;
Scott Haseley20ccbe322023-04-26 20:25:1428using QueueEnabledVoter = base::sequence_manager::TaskQueue::QueueEnabledVoter;
Carlos Caballero72e8a202019-05-21 16:51:1729
Aman Verma566a5d22022-09-22 16:30:4830QueueName GetControlTaskQueueName(BrowserThread::ID thread_id) {
Carlos Caballero5f6212b2019-05-13 13:45:1631 switch (thread_id) {
32 case BrowserThread::UI:
Aman Verma566a5d22022-09-22 16:30:4833 return QueueName::UI_CONTROL_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1634 case BrowserThread::IO:
Aman Verma566a5d22022-09-22 16:30:4835 return QueueName::IO_CONTROL_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1636 case BrowserThread::ID_COUNT:
37 break;
38 }
Peter Boströmfc7ddc182024-10-31 19:37:2139 NOTREACHED();
Carlos Caballero5f6212b2019-05-13 13:45:1640}
41
Aman Verma566a5d22022-09-22 16:30:4842QueueName GetRunAllPendingTaskQueueName(BrowserThread::ID thread_id) {
Carlos Caballero5f6212b2019-05-13 13:45:1643 switch (thread_id) {
44 case BrowserThread::UI:
Aman Verma566a5d22022-09-22 16:30:4845 return QueueName::UI_RUN_ALL_PENDING_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1646 case BrowserThread::IO:
Aman Verma566a5d22022-09-22 16:30:4847 return QueueName::IO_RUN_ALL_PENDING_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1648 case BrowserThread::ID_COUNT:
49 break;
50 }
Peter Boströmfc7ddc182024-10-31 19:37:2151 NOTREACHED();
Carlos Caballero5f6212b2019-05-13 13:45:1652}
53
Aman Verma566a5d22022-09-22 16:30:4854QueueName GetUITaskQueueName(BrowserTaskQueues::QueueType queue_type) {
Carlos Caballero5f6212b2019-05-13 13:45:1655 switch (queue_type) {
56 case BrowserTaskQueues::QueueType::kBestEffort:
Aman Verma566a5d22022-09-22 16:30:4857 return QueueName::UI_BEST_EFFORT_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1658 case BrowserTaskQueues::QueueType::kDefault:
Aman Verma566a5d22022-09-22 16:30:4859 return QueueName::UI_DEFAULT_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1660 case BrowserTaskQueues::QueueType::kUserBlocking:
Aman Verma566a5d22022-09-22 16:30:4861 return QueueName::UI_USER_BLOCKING_TQ;
Alex Clarkeb7eb45c2019-07-10 15:19:2462 case BrowserTaskQueues::QueueType::kUserVisible:
Aman Verma566a5d22022-09-22 16:30:4863 return QueueName::UI_USER_VISIBLE_TQ;
Stephen Nuskod43825b2021-06-24 19:10:3764 case BrowserTaskQueues::QueueType::kUserInput:
Aman Verma566a5d22022-09-22 16:30:4865 return QueueName::UI_USER_INPUT_TQ;
Clark DuVall6429553c2021-10-06 02:53:1566 case BrowserTaskQueues::QueueType::kNavigationNetworkResponse:
Aman Verma566a5d22022-09-22 16:30:4867 return QueueName::UI_NAVIGATION_NETWORK_RESPONSE_TQ;
Minoru Chikamunea0317562022-03-22 15:30:2168 case BrowserTaskQueues::QueueType::kServiceWorkerStorageControlResponse:
Aman Verma566a5d22022-09-22 16:30:4869 return QueueName::UI_SERVICE_WORKER_STORAGE_CONTROL_RESPONSE_TQ;
Ryan Sturmac5b1662023-06-13 23:31:4770 case BrowserTaskQueues::QueueType::kBeforeUnloadBrowserResponse:
71 return QueueName::UI_BEFORE_UNLOAD_BROWSER_RESPONSE_TQ;
Chidera Olibief6c4cdb2025-06-25 22:56:0872 case BrowserTaskQueues::QueueType::kStartup:
73 return QueueName::UI_STARTUP_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1674 }
75}
76
Aman Verma566a5d22022-09-22 16:30:4877QueueName GetIOTaskQueueName(BrowserTaskQueues::QueueType queue_type) {
Carlos Caballero5f6212b2019-05-13 13:45:1678 switch (queue_type) {
79 case BrowserTaskQueues::QueueType::kBestEffort:
Aman Verma566a5d22022-09-22 16:30:4880 return QueueName::IO_BEST_EFFORT_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1681 case BrowserTaskQueues::QueueType::kDefault:
Aman Verma566a5d22022-09-22 16:30:4882 return QueueName::IO_DEFAULT_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1683 case BrowserTaskQueues::QueueType::kUserBlocking:
Aman Verma566a5d22022-09-22 16:30:4884 return QueueName::IO_USER_BLOCKING_TQ;
Alex Clarkeb7eb45c2019-07-10 15:19:2485 case BrowserTaskQueues::QueueType::kUserVisible:
Aman Verma566a5d22022-09-22 16:30:4886 return QueueName::IO_USER_VISIBLE_TQ;
Stephen Nuskod43825b2021-06-24 19:10:3787 case BrowserTaskQueues::QueueType::kUserInput:
Aman Verma566a5d22022-09-22 16:30:4888 return QueueName::IO_USER_INPUT_TQ;
Clark DuVall6429553c2021-10-06 02:53:1589 case BrowserTaskQueues::QueueType::kNavigationNetworkResponse:
Aman Verma566a5d22022-09-22 16:30:4890 return QueueName::IO_NAVIGATION_NETWORK_RESPONSE_TQ;
Minoru Chikamunea0317562022-03-22 15:30:2191 case BrowserTaskQueues::QueueType::kServiceWorkerStorageControlResponse:
Aman Verma566a5d22022-09-22 16:30:4892 return QueueName::IO_SERVICE_WORKER_STORAGE_CONTROL_RESPONSE_TQ;
Ryan Sturmac5b1662023-06-13 23:31:4793 case BrowserTaskQueues::QueueType::kBeforeUnloadBrowserResponse:
94 return QueueName::IO_BEFORE_UNLOAD_BROWSER_RESPONSE_TQ;
Chidera Olibief6c4cdb2025-06-25 22:56:0895 case BrowserTaskQueues::QueueType::kStartup:
96 return QueueName::IO_STARTUP_TQ;
Carlos Caballero5f6212b2019-05-13 13:45:1697 }
98}
99
Aman Verma566a5d22022-09-22 16:30:48100QueueName GetTaskQueueName(BrowserThread::ID thread_id,
101 BrowserTaskQueues::QueueType queue_type) {
Carlos Caballero5f6212b2019-05-13 13:45:16102 switch (thread_id) {
103 case BrowserThread::UI:
104 return GetUITaskQueueName(queue_type);
105 case BrowserThread::IO:
106 return GetIOTaskQueueName(queue_type);
107 case BrowserThread::ID_COUNT:
108 break;
109 }
Peter Boströmfc7ddc182024-10-31 19:37:21110 NOTREACHED();
Carlos Caballero5f6212b2019-05-13 13:45:16111}
112
113} // namespace
114
Omar Elmekkawyb081b583a2022-12-17 13:01:27115BrowserTaskQueues::QueueData::QueueData() = default;
116BrowserTaskQueues::QueueData::~QueueData() = default;
Scott Haseley20ccbe322023-04-26 20:25:14117BrowserTaskQueues::QueueData::QueueData(BrowserTaskQueues::QueueData&& other) =
118 default;
119
Carlos Caballero5f6212b2019-05-13 13:45:16120BrowserTaskQueues::Handle::~Handle() = default;
Carlos Caballero5f6212b2019-05-13 13:45:16121
122BrowserTaskQueues::Handle::Handle(BrowserTaskQueues* outer)
123 : outer_(outer),
124 control_task_runner_(outer_->control_queue_->task_runner()),
Scott Haseley20ccbe322023-04-26 20:25:14125 default_task_runner_(outer_->GetDefaultTaskQueue()->task_runner()),
Carlos Caballero72e8a202019-05-21 16:51:17126 browser_task_runners_(outer_->CreateBrowserTaskRunners()) {}
Carlos Caballero5f6212b2019-05-13 13:45:16127
Minoru Chikamunea0317562022-03-22 15:30:21128void BrowserTaskQueues::Handle::OnStartupComplete() {
Carlos Caballero5f6212b2019-05-13 13:45:16129 control_task_runner_->PostTask(
Minoru Chikamunea0317562022-03-22 15:30:21130 FROM_HERE, base::BindOnce(&BrowserTaskQueues::OnStartupComplete,
Carlos Caballero5f6212b2019-05-13 13:45:16131 base::Unretained(outer_)));
132}
133
Carlos Caballero72e8a202019-05-21 16:51:17134void BrowserTaskQueues::Handle::EnableAllExceptBestEffortQueues() {
135 control_task_runner_->PostTask(
136 FROM_HERE,
137 base::BindOnce(&BrowserTaskQueues::EnableAllExceptBestEffortQueues,
138 base::Unretained(outer_)));
139}
140
Chidera Olibiedebdc542025-03-25 23:14:08141void BrowserTaskQueues::Handle::EnableTaskQueue(QueueType type) {
142 control_task_runner_->PostTask(
143 FROM_HERE, base::BindOnce(&BrowserTaskQueues::EnableTaskQueue,
144 base::Unretained(outer_), type));
145}
146
Carlos Caballero5f6212b2019-05-13 13:45:16147void BrowserTaskQueues::Handle::ScheduleRunAllPendingTasksForTesting(
148 base::OnceClosure on_pending_task_ran) {
149 control_task_runner_->PostTask(
150 FROM_HERE,
151 base::BindOnce(
152 &BrowserTaskQueues::StartRunAllPendingTasksForTesting,
153 base::Unretained(outer_),
154 base::ScopedClosureRunner(std::move(on_pending_task_ran))));
155}
156
157BrowserTaskQueues::BrowserTaskQueues(
158 BrowserThread::ID thread_id,
Etienne Pierre-doray40545ac2021-11-11 13:34:28159 base::sequence_manager::SequenceManager* sequence_manager) {
Alex Clarke49854cc2019-06-27 08:25:49160 for (size_t i = 0; i < queue_data_.size(); ++i) {
Scott Haseley20ccbe322023-04-26 20:25:14161 queue_data_[i].task_queue = sequence_manager->CreateTaskQueue(
Carlos Caballero5f6212b2019-05-13 13:45:16162 base::sequence_manager::TaskQueue::Spec(
Etienne Pierre-doray40545ac2021-11-11 13:34:28163 GetTaskQueueName(thread_id, static_cast<QueueType>(i))));
Scott Haseley20ccbe322023-04-26 20:25:14164 queue_data_[i].voter = queue_data_[i].task_queue->CreateQueueEnabledVoter();
Chidera Olibiedebdc542025-03-25 23:14:08165 queue_data_[i].voter->SetVoteToEnable(false);
Carlos Caballero5f6212b2019-05-13 13:45:16166 }
167
Alex Clarkeb7eb45c2019-07-10 15:19:24168 GetBrowserTaskQueue(QueueType::kUserVisible)
Scott Haseley72d89b02023-02-17 03:29:25169 ->SetQueuePriority(BrowserTaskPriority::kLowPriority);
Alex Clarkeb7eb45c2019-07-10 15:19:24170
Carlos Caballero5f6212b2019-05-13 13:45:16171 // Best effort queue
Carlos Caballero72e8a202019-05-21 16:51:17172 GetBrowserTaskQueue(QueueType::kBestEffort)
Scott Haseley72d89b02023-02-17 03:29:25173 ->SetQueuePriority(BrowserTaskPriority::kBestEffortPriority);
Carlos Caballero5f6212b2019-05-13 13:45:16174
Stephen Nuskod43825b2021-06-24 19:10:37175 // User Input queue
176 GetBrowserTaskQueue(QueueType::kUserInput)
Scott Haseley72d89b02023-02-17 03:29:25177 ->SetQueuePriority(BrowserTaskPriority::kHighestPriority);
Stephen Nuskod43825b2021-06-24 19:10:37178
Clark DuVall6429553c2021-10-06 02:53:15179 GetBrowserTaskQueue(QueueType::kNavigationNetworkResponse)
Scott Haseley72d89b02023-02-17 03:29:25180 ->SetQueuePriority(BrowserTaskPriority::kHighPriority);
Clark DuVall6429553c2021-10-06 02:53:15181
Minoru Chikamunea0317562022-03-22 15:30:21182 GetBrowserTaskQueue(QueueType::kServiceWorkerStorageControlResponse)
Scott Haseley72d89b02023-02-17 03:29:25183 ->SetQueuePriority(BrowserTaskPriority::kHighestPriority);
Minoru Chikamunea0317562022-03-22 15:30:21184
Ryan Sturmac5b1662023-06-13 23:31:47185 GetBrowserTaskQueue(QueueType::kBeforeUnloadBrowserResponse)
186 ->SetQueuePriority(BrowserTaskPriority::kHighPriority);
187
Carlos Caballero5f6212b2019-05-13 13:45:16188 // Control queue
189 control_queue_ =
190 sequence_manager->CreateTaskQueue(base::sequence_manager::TaskQueue::Spec(
Etienne Pierre-doray40545ac2021-11-11 13:34:28191 GetControlTaskQueueName(thread_id)));
Scott Haseley72d89b02023-02-17 03:29:25192 control_queue_->SetQueuePriority(BrowserTaskPriority::kControlPriority);
Carlos Caballero5f6212b2019-05-13 13:45:16193
194 // Run all pending queue
Etienne Pierre-doray40545ac2021-11-11 13:34:28195 run_all_pending_tasks_queue_ =
196 sequence_manager->CreateTaskQueue(base::sequence_manager::TaskQueue::Spec(
197 GetRunAllPendingTaskQueueName(thread_id)));
Carlos Caballero5f6212b2019-05-13 13:45:16198 run_all_pending_tasks_queue_->SetQueuePriority(
Scott Haseley72d89b02023-02-17 03:29:25199 BrowserTaskPriority::kBestEffortPriority);
Alex Clarke49854cc2019-06-27 08:25:49200
201 handle_ = base::AdoptRef(new Handle(this));
Carlos Caballero5f6212b2019-05-13 13:45:16202}
203
204BrowserTaskQueues::~BrowserTaskQueues() {
Alex Clarke49854cc2019-06-27 08:25:49205 for (auto& queue : queue_data_) {
Scott Haseleyf473cfeba2023-09-21 16:01:47206 queue.task_queue.reset();
Carlos Caballero5f6212b2019-05-13 13:45:16207 }
Scott Haseleyf473cfeba2023-09-21 16:01:47208 control_queue_.reset();
209 run_all_pending_tasks_queue_.reset();
Tom Sepeza80667c2023-02-13 19:18:46210 handle_->OnTaskQueuesDestroyed();
Carlos Caballero5f6212b2019-05-13 13:45:16211}
212
213std::array<scoped_refptr<base::SingleThreadTaskRunner>,
214 BrowserTaskQueues::kNumQueueTypes>
Carlos Caballero72e8a202019-05-21 16:51:17215BrowserTaskQueues::CreateBrowserTaskRunners() const {
Carlos Caballero5f6212b2019-05-13 13:45:16216 std::array<scoped_refptr<base::SingleThreadTaskRunner>, kNumQueueTypes>
217 task_runners;
Alex Clarke49854cc2019-06-27 08:25:49218 for (size_t i = 0; i < queue_data_.size(); ++i) {
Scott Haseley20ccbe322023-04-26 20:25:14219 task_runners[i] = queue_data_[i].task_queue->task_runner();
Carlos Caballero5f6212b2019-05-13 13:45:16220 }
221 return task_runners;
222}
223
Minoru Chikamunea0317562022-03-22 15:30:21224void BrowserTaskQueues::OnStartupComplete() {
225 // Enable all queues
226 for (const auto& queue : queue_data_) {
Scott Haseley20ccbe322023-04-26 20:25:14227 queue.voter->SetVoteToEnable(true);
Carlos Caballero72e8a202019-05-21 16:51:17228 }
Minoru Chikamunea0317562022-03-22 15:30:21229
230 // Update ServiceWorker task queue priority.
Scott Haseley72d89b02023-02-17 03:29:25231 DCHECK_EQ(
232 static_cast<BrowserTaskPriority>(
233 GetBrowserTaskQueue(QueueType::kServiceWorkerStorageControlResponse)
234 ->GetQueuePriority()),
235 BrowserTaskPriority::kHighestPriority);
Minoru Chikamunea0317562022-03-22 15:30:21236 GetBrowserTaskQueue(QueueType::kServiceWorkerStorageControlResponse)
Nathan Memmotta9eec542024-12-13 18:17:28237 ->SetQueuePriority(BrowserTaskPriority::kHighPriority);
Carlos Caballero72e8a202019-05-21 16:51:17238}
239
Chidera Olibiedebdc542025-03-25 23:14:08240void BrowserTaskQueues::EnableTaskQueue(QueueType type) {
241 queue_data_[static_cast<size_t>(type)].voter->SetVoteToEnable(true);
242}
243
Carlos Caballero72e8a202019-05-21 16:51:17244void BrowserTaskQueues::EnableAllExceptBestEffortQueues() {
Alex Clarke49854cc2019-06-27 08:25:49245 for (size_t i = 0; i < queue_data_.size(); ++i) {
Scott Haseley20ccbe322023-04-26 20:25:14246 if (i != static_cast<size_t>(QueueType::kBestEffort)) {
247 queue_data_[i].voter->SetVoteToEnable(true);
248 }
Carlos Caballero72e8a202019-05-21 16:51:17249 }
Carlos Caballero5f6212b2019-05-13 13:45:16250}
251
252// To run all pending tasks we do the following. We insert a fence in all queues
253// and post a task to the |run_all_pending_queue_| which has the lowest priority
254// possible. That makes sure that all tasks up to the fences will have run
255// before this posted task runs. Note that among tasks with the same priority
256// ties are broken by using the enqueue order, so all prior best effort tasks
257// will have run before this one does. This task will then remove all the fences
258// and call the user provided callback to signal that all pending tasks have
259// run. This method is "reentrant" as in we can call it multiple times as the
260// fences will just be moved back, but we need to make sure that only the last
261// call removes the fences, for that we keep track of "nesting" with
262// |run_all_pending_nesting_level_|
263void BrowserTaskQueues::StartRunAllPendingTasksForTesting(
264 base::ScopedClosureRunner on_pending_task_ran) {
265 ++run_all_pending_nesting_level_;
Alex Clarke49854cc2019-06-27 08:25:49266 for (const auto& queue : queue_data_) {
Scott Haseley20ccbe322023-04-26 20:25:14267 queue.task_queue->InsertFence(InsertFencePosition::kNow);
Carlos Caballero5f6212b2019-05-13 13:45:16268 }
269 run_all_pending_tasks_queue_->task_runner()->PostTask(
270 FROM_HERE,
271 base::BindOnce(&BrowserTaskQueues::EndRunAllPendingTasksForTesting,
272 base::Unretained(this), std::move(on_pending_task_ran)));
273}
274
275void BrowserTaskQueues::EndRunAllPendingTasksForTesting(
276 base::ScopedClosureRunner on_pending_task_ran) {
277 --run_all_pending_nesting_level_;
278 if (run_all_pending_nesting_level_ == 0) {
Alex Clarke49854cc2019-06-27 08:25:49279 for (const auto& queue : queue_data_) {
Scott Haseley20ccbe322023-04-26 20:25:14280 queue.task_queue->RemoveFence();
Carlos Caballero5f6212b2019-05-13 13:45:16281 }
Carlos Caballero5f6212b2019-05-13 13:45:16282 }
283}
284
Anand Ravi5e3bf102025-05-02 15:24:49285void BrowserTaskQueues::SetOnTaskCompletedHandler(
286 base::sequence_manager::TaskQueue::OnTaskCompletedHandler handler) {
287 for (auto& queue : queue_data_) {
288 queue.task_queue->SetOnTaskCompletedHandler(handler);
289 }
290}
291
mikt541ac712025-08-04 03:16:22292void BrowserTaskQueues::AddTaskObserver(base::TaskObserver* task_observer) {
293 for (const auto& queue : queue_data_) {
294 queue.task_queue->AddTaskObserver(task_observer);
295 }
296}
297
Alex Clarke49854cc2019-06-27 08:25:49298} // namespace content