1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/task/sequence_manager/sequence_manager_impl.h"
11
12 #include <array>
13 #include <atomic>
14 #include <optional>
15 #include <queue>
16 #include <string_view>
17 #include <vector>
18
19 #include "base/callback_list.h"
20 #include "base/compiler_specific.h"
21 #include "base/debug/crash_logging.h"
22 #include "base/debug/stack_trace.h"
23 #include "base/functional/bind.h"
24 #include "base/functional/callback.h"
25 #include "base/functional/callback_helpers.h"
26 #include "base/json/json_writer.h"
27 #include "base/logging.h"
28 #include "base/memory/ptr_util.h"
29 #include "base/notreached.h"
30 #include "base/observer_list.h"
31 #include "base/rand_util.h"
32 #include "base/ranges/algorithm.h"
33 #include "base/task/sequence_manager/enqueue_order.h"
34 #include "base/task/sequence_manager/task_queue_impl.h"
35 #include "base/task/sequence_manager/task_time_observer.h"
36 #include "base/task/sequence_manager/thread_controller_impl.h"
37 #include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
38 #include "base/task/sequence_manager/time_domain.h"
39 #include "base/task/sequence_manager/wake_up_queue.h"
40 #include "base/task/sequence_manager/work_queue.h"
41 #include "base/task/sequence_manager/work_queue_sets.h"
42 #include "base/task/task_features.h"
43 #include "base/threading/thread_id_name_manager.h"
44 #include "base/time/default_tick_clock.h"
45 #include "base/time/tick_clock.h"
46 #include "base/trace_event/base_tracing.h"
47 #include "build/build_config.h"
48
49 namespace base {
50 namespace sequence_manager {
51 namespace {
52
53 // Whether SequenceManagerImpl records crash keys. Enable via Finch when needed
54 // for an investigation. Disabled by default to avoid unnecessary overhead.
55 BASE_FEATURE(kRecordSequenceManagerCrashKeys,
56 "RecordSequenceManagerCrashKeys",
57 base::FEATURE_DISABLED_BY_DEFAULT);
58
59 constinit thread_local internal::SequenceManagerImpl*
60 thread_local_sequence_manager = nullptr;
61
62 class TracedBaseValue : public trace_event::ConvertableToTraceFormat {
63 public:
TracedBaseValue(Value value)64 explicit TracedBaseValue(Value value) : value_(std::move(value)) {}
65 ~TracedBaseValue() override = default;
66
AppendAsTraceFormat(std::string * out) const67 void AppendAsTraceFormat(std::string* out) const override {
68 if (!value_.is_none()) {
69 std::string tmp;
70 JSONWriter::Write(value_, &tmp);
71 *out += tmp;
72 } else {
73 *out += "{}";
74 }
75 }
76
77 private:
78 base::Value value_;
79 };
80
81 } // namespace
82
CreateSequenceManagerOnCurrentThread(SequenceManager::Settings settings)83 std::unique_ptr<SequenceManager> CreateSequenceManagerOnCurrentThread(
84 SequenceManager::Settings settings) {
85 return internal::SequenceManagerImpl::CreateOnCurrentThread(
86 std::move(settings));
87 }
88
CreateSequenceManagerOnCurrentThreadWithPump(std::unique_ptr<MessagePump> message_pump,SequenceManager::Settings settings)89 std::unique_ptr<SequenceManager> CreateSequenceManagerOnCurrentThreadWithPump(
90 std::unique_ptr<MessagePump> message_pump,
91 SequenceManager::Settings settings) {
92 std::unique_ptr<SequenceManager> manager =
93 internal::SequenceManagerImpl::CreateUnbound(std::move(settings));
94 manager->BindToMessagePump(std::move(message_pump));
95 return manager;
96 }
97
CreateUnboundSequenceManager(SequenceManager::Settings settings)98 std::unique_ptr<SequenceManager> CreateUnboundSequenceManager(
99 SequenceManager::Settings settings) {
100 return internal::SequenceManagerImpl::CreateUnbound(std::move(settings));
101 }
102
103 namespace internal {
104
CreateUnboundSequenceManagerImpl(PassKey<base::internal::SequenceManagerThreadDelegate>,SequenceManager::Settings settings)105 std::unique_ptr<SequenceManagerImpl> CreateUnboundSequenceManagerImpl(
106 PassKey<base::internal::SequenceManagerThreadDelegate>,
107 SequenceManager::Settings settings) {
108 return SequenceManagerImpl::CreateUnbound(std::move(settings));
109 }
110
111 using TimeRecordingPolicy =
112 base::sequence_manager::TaskQueue::TaskTiming::TimeRecordingPolicy;
113
114 namespace {
115
116 constexpr TimeDelta kLongTaskTraceEventThreshold = Milliseconds(50);
117 // Proportion of tasks which will record thread time for metrics.
118 const double kTaskSamplingRateForRecordingCPUTime = 0.01;
119 // Proprortion of SequenceManagers which will record thread time for each task,
120 // enabling advanced metrics.
121 const double kThreadSamplingRateForRecordingCPUTime = 0.0001;
122
ReclaimMemoryFromQueue(internal::TaskQueueImpl * queue,LazyNow * lazy_now)123 void ReclaimMemoryFromQueue(internal::TaskQueueImpl* queue, LazyNow* lazy_now) {
124 queue->ReclaimMemory(lazy_now->Now());
125 // If the queue was shut down as a side-effect of reclaiming memory, |queue|
126 // will still be valid but the work queues will have been removed by
127 // TaskQueueImpl::UnregisterTaskQueue.
128 if (queue->delayed_work_queue()) {
129 queue->delayed_work_queue()->RemoveAllCanceledTasksFromFront();
130 queue->immediate_work_queue()->RemoveAllCanceledTasksFromFront();
131 }
132 }
133
InitializeMetricRecordingSettings(bool randomised_sampling_enabled)134 SequenceManager::MetricRecordingSettings InitializeMetricRecordingSettings(
135 bool randomised_sampling_enabled) {
136 if (!randomised_sampling_enabled)
137 return SequenceManager::MetricRecordingSettings(0);
138 bool records_cpu_time_for_each_task =
139 base::RandDouble() < kThreadSamplingRateForRecordingCPUTime;
140 return SequenceManager::MetricRecordingSettings(
141 records_cpu_time_for_each_task ? 1
142 : kTaskSamplingRateForRecordingCPUTime);
143 }
144
145 // Writes |address| in hexadecimal ("0x11223344") form starting from |output|
146 // and moving backwards in memory. Returns a pointer to the first digit of the
147 // result. Does *not* NUL-terminate the number.
148 #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
PrependHexAddress(char * output,const void * address)149 char* PrependHexAddress(char* output, const void* address) {
150 uintptr_t value = reinterpret_cast<uintptr_t>(address);
151 static const char kHexChars[] = "0123456789ABCDEF";
152 do {
153 *output-- = kHexChars[value % 16];
154 value /= 16;
155 } while (value);
156 *output-- = 'x';
157 *output = '0';
158 return output;
159 }
160 #endif // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
161
162 // Atomic to avoid TSAN flags when a test tries to access the value before the
163 // feature list is available.
164 std::atomic_bool g_record_crash_keys = false;
165
166 #if BUILDFLAG(IS_WIN)
167 bool g_explicit_high_resolution_timer_win = true;
168 #endif // BUILDFLAG(IS_WIN)
169
170 } // namespace
171
172 // static
GetCurrent()173 SequenceManagerImpl* SequenceManagerImpl::GetCurrent() {
174 // Workaround false-positive MSAN use-of-uninitialized-value on
175 // thread_local storage for loaded libraries:
176 // https://github.com/google/sanitizers/issues/1265
177 MSAN_UNPOISON(&thread_local_sequence_manager, sizeof(SequenceManagerImpl*));
178
179 return thread_local_sequence_manager;
180 }
181
SequenceManagerImpl(std::unique_ptr<internal::ThreadController> controller,SequenceManager::Settings settings)182 SequenceManagerImpl::SequenceManagerImpl(
183 std::unique_ptr<internal::ThreadController> controller,
184 SequenceManager::Settings settings)
185 : associated_thread_(controller->GetAssociatedThread()),
186 controller_(std::move(controller)),
187 settings_(std::move(settings)),
188 metric_recording_settings_(InitializeMetricRecordingSettings(
189 settings_.randomised_sampling_enabled)),
190 add_queue_time_to_tasks_(settings_.add_queue_time_to_tasks),
191
192 empty_queues_to_reload_(associated_thread_),
193 main_thread_only_(this, associated_thread_, settings_, settings_.clock),
194 clock_(settings_.clock) {
195 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
196 TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "SequenceManager", this);
197 main_thread_only().selector.SetTaskQueueSelectorObserver(this);
198
199 main_thread_only().next_time_to_reclaim_memory =
200 main_thread_clock()->NowTicks() + kReclaimMemoryInterval;
201
202 controller_->SetSequencedTaskSource(this);
203 }
204
~SequenceManagerImpl()205 SequenceManagerImpl::~SequenceManagerImpl() {
206 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
207 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
208 TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "SequenceManager", this);
209
210 #if BUILDFLAG(IS_IOS)
211 if (settings_.message_loop_type == MessagePumpType::UI &&
212 associated_thread_->IsBound()) {
213 controller_->DetachFromMessagePump();
214 }
215 #endif
216
217 // Make sure no Task is running as given that RunLoop does not support the
218 // Delegate being destroyed from a Task and
219 // ThreadControllerWithMessagePumpImpl does not support being destroyed from a
220 // Task. If we are using a ThreadControllerImpl (i.e. no pump) destruction is
221 // fine
222 DCHECK(!controller_->GetBoundMessagePump() ||
223 main_thread_only().task_execution_stack.empty());
224
225 for (internal::TaskQueueImpl* queue : main_thread_only().active_queues) {
226 main_thread_only().selector.RemoveQueue(queue);
227 queue->UnregisterTaskQueue();
228 }
229
230 // TODO(altimin): restore default task runner automatically when
231 // ThreadController is destroyed.
232 controller_->RestoreDefaultTaskRunner();
233
234 main_thread_only().active_queues.clear();
235 main_thread_only().selector.SetTaskQueueSelectorObserver(nullptr);
236
237 // In the case of an early startup exits or in some tests a NestingObserver
238 // may not have been registered.
239 if (main_thread_only().nesting_observer_registered_)
240 controller_->RemoveNestingObserver(this);
241
242 // Let interested parties have one last shot at accessing this.
243 for (auto& observer : main_thread_only().destruction_observers)
244 observer.WillDestroyCurrentMessageLoop();
245
246 // OK, now make it so that no one can find us.
247 if (GetMessagePump()) {
248 DCHECK_EQ(this, GetCurrent());
249 thread_local_sequence_manager = nullptr;
250 }
251 }
252
MainThreadOnly(SequenceManagerImpl * sequence_manager,const scoped_refptr<AssociatedThreadId> & associated_thread,const SequenceManager::Settings & settings,const base::TickClock * clock)253 SequenceManagerImpl::MainThreadOnly::MainThreadOnly(
254 SequenceManagerImpl* sequence_manager,
255 const scoped_refptr<AssociatedThreadId>& associated_thread,
256 const SequenceManager::Settings& settings,
257 const base::TickClock* clock)
258 : selector(associated_thread, settings),
259 default_clock(clock),
260 time_domain(nullptr),
261 wake_up_queue(std::make_unique<DefaultWakeUpQueue>(associated_thread,
262 sequence_manager)),
263 non_waking_wake_up_queue(
264 std::make_unique<NonWakingWakeUpQueue>(associated_thread)) {
265 if (settings.randomised_sampling_enabled) {
266 metrics_subsampler = base::MetricsSubSampler();
267 }
268 }
269
270 SequenceManagerImpl::MainThreadOnly::~MainThreadOnly() = default;
271
272 // static
273 std::unique_ptr<ThreadControllerImpl>
CreateThreadControllerImplForCurrentThread(const TickClock * clock)274 SequenceManagerImpl::CreateThreadControllerImplForCurrentThread(
275 const TickClock* clock) {
276 return ThreadControllerImpl::Create(GetCurrent(), clock);
277 }
278
279 // static
CreateOnCurrentThread(SequenceManager::Settings settings)280 std::unique_ptr<SequenceManagerImpl> SequenceManagerImpl::CreateOnCurrentThread(
281 SequenceManager::Settings settings) {
282 auto thread_controller =
283 CreateThreadControllerImplForCurrentThread(settings.clock);
284 std::unique_ptr<SequenceManagerImpl> manager(new SequenceManagerImpl(
285 std::move(thread_controller), std::move(settings)));
286 manager->BindToCurrentThread();
287 return manager;
288 }
289
290 // static
CreateUnbound(SequenceManager::Settings settings)291 std::unique_ptr<SequenceManagerImpl> SequenceManagerImpl::CreateUnbound(
292 SequenceManager::Settings settings) {
293 auto thread_controller =
294 ThreadControllerWithMessagePumpImpl::CreateUnbound(settings);
295 return WrapUnique(new SequenceManagerImpl(std::move(thread_controller),
296 std::move(settings)));
297 }
298
299 // static
InitializeFeatures()300 void SequenceManagerImpl::InitializeFeatures() {
301 TaskQueueImpl::InitializeFeatures();
302 MessagePump::InitializeFeatures();
303 ThreadControllerWithMessagePumpImpl::InitializeFeatures();
304 #if BUILDFLAG(IS_WIN)
305 g_explicit_high_resolution_timer_win =
306 FeatureList::IsEnabled(kExplicitHighResolutionTimerWin);
307 #endif // BUILDFLAG(IS_WIN)
308
309 g_record_crash_keys.store(
310 FeatureList::IsEnabled(kRecordSequenceManagerCrashKeys),
311 std::memory_order_relaxed);
312 }
313
BindToMessagePump(std::unique_ptr<MessagePump> pump)314 void SequenceManagerImpl::BindToMessagePump(std::unique_ptr<MessagePump> pump) {
315 controller_->BindToCurrentThread(std::move(pump));
316 CompleteInitializationOnBoundThread();
317
318 // On Android attach to the native loop when there is one.
319 #if BUILDFLAG(IS_ANDROID)
320 if (settings_.message_loop_type == MessagePumpType::UI ||
321 settings_.message_loop_type == MessagePumpType::JAVA) {
322 controller_->AttachToMessagePump();
323 }
324 #endif
325
326 // On iOS attach to the native loop when there is one.
327 #if BUILDFLAG(IS_IOS)
328 if (settings_.message_loop_type == MessagePumpType::UI) {
329 controller_->AttachToMessagePump();
330 }
331 #endif
332 }
333
BindToCurrentThread()334 void SequenceManagerImpl::BindToCurrentThread() {
335 associated_thread_->BindToCurrentThread();
336 CompleteInitializationOnBoundThread();
337 }
338
339 scoped_refptr<SequencedTaskRunner>
GetTaskRunnerForCurrentTask()340 SequenceManagerImpl::GetTaskRunnerForCurrentTask() {
341 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
342 if (main_thread_only().task_execution_stack.empty())
343 return nullptr;
344 return main_thread_only()
345 .task_execution_stack.back()
346 .pending_task.task_runner;
347 }
348
CompleteInitializationOnBoundThread()349 void SequenceManagerImpl::CompleteInitializationOnBoundThread() {
350 controller_->AddNestingObserver(this);
351 main_thread_only().nesting_observer_registered_ = true;
352 if (GetMessagePump()) {
353 DCHECK(!GetCurrent())
354 << "Can't register a second SequenceManagerImpl on the same thread.";
355 thread_local_sequence_manager = this;
356 }
357 for (internal::TaskQueueImpl* queue : main_thread_only().active_queues) {
358 queue->CompleteInitializationOnBoundThread();
359 }
360 }
361
SetTimeDomain(TimeDomain * time_domain)362 void SequenceManagerImpl::SetTimeDomain(TimeDomain* time_domain) {
363 DCHECK(!main_thread_only().time_domain);
364 DCHECK(time_domain);
365 time_domain->OnAssignedToSequenceManager(this);
366 controller_->SetTickClock(time_domain);
367 main_thread_only().time_domain = time_domain;
368 clock_.store(time_domain, std::memory_order_release);
369 }
370
ResetTimeDomain()371 void SequenceManagerImpl::ResetTimeDomain() {
372 controller_->SetTickClock(main_thread_only().default_clock);
373 clock_.store(main_thread_only().default_clock.get(),
374 std::memory_order_release);
375 main_thread_only().time_domain = nullptr;
376 }
377
378 std::unique_ptr<internal::TaskQueueImpl>
CreateTaskQueueImpl(const TaskQueue::Spec & spec)379 SequenceManagerImpl::CreateTaskQueueImpl(const TaskQueue::Spec& spec) {
380 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
381 std::unique_ptr<internal::TaskQueueImpl> task_queue =
382 std::make_unique<internal::TaskQueueImpl>(
383 this,
384 spec.non_waking ? main_thread_only().non_waking_wake_up_queue.get()
385 : main_thread_only().wake_up_queue.get(),
386 spec);
387 main_thread_only().active_queues.insert(task_queue.get());
388 main_thread_only().selector.AddQueue(
389 task_queue.get(), settings().priority_settings.default_priority());
390 return task_queue;
391 }
392
SetAddQueueTimeToTasks(bool enable)393 void SequenceManagerImpl::SetAddQueueTimeToTasks(bool enable) {
394 add_queue_time_to_tasks_.store(enable, std::memory_order_relaxed);
395 }
396
GetAddQueueTimeToTasks()397 bool SequenceManagerImpl::GetAddQueueTimeToTasks() {
398 return add_queue_time_to_tasks_.load(std::memory_order_relaxed);
399 }
400
SetObserver(Observer * observer)401 void SequenceManagerImpl::SetObserver(Observer* observer) {
402 main_thread_only().observer = observer;
403 }
404
UnregisterTaskQueueImpl(std::unique_ptr<internal::TaskQueueImpl> task_queue)405 void SequenceManagerImpl::UnregisterTaskQueueImpl(
406 std::unique_ptr<internal::TaskQueueImpl> task_queue) {
407 TRACE_EVENT1("sequence_manager", "SequenceManagerImpl::UnregisterTaskQueue",
408 "queue_name", task_queue->GetName());
409 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
410
411 main_thread_only().selector.RemoveQueue(task_queue.get());
412
413 // After UnregisterTaskQueue returns no new tasks can be posted.
414 // It's important to call it first to avoid race condition between removing
415 // the task queue from various lists here and adding it to the same lists
416 // when posting a task.
417 task_queue->UnregisterTaskQueue();
418
419 // Add |task_queue| to |main_thread_only().queues_to_delete| so we can prevent
420 // it from being freed while any of our structures hold hold a raw pointer to
421 // it.
422 main_thread_only().active_queues.erase(task_queue.get());
423 main_thread_only().queues_to_delete[task_queue.get()] = std::move(task_queue);
424 }
425
426 AtomicFlagSet::AtomicFlag
GetFlagToRequestReloadForEmptyQueue(TaskQueueImpl * task_queue)427 SequenceManagerImpl::GetFlagToRequestReloadForEmptyQueue(
428 TaskQueueImpl* task_queue) {
429 return empty_queues_to_reload_.AddFlag(BindRepeating(
430 &TaskQueueImpl::ReloadEmptyImmediateWorkQueue, Unretained(task_queue)));
431 }
432
ReloadEmptyWorkQueues()433 void SequenceManagerImpl::ReloadEmptyWorkQueues() {
434 work_tracker_.WillReloadImmediateWorkQueues();
435
436 // There are two cases where a queue needs reloading. First, it might be
437 // completely empty and we've just posted a task (this method handles that
438 // case). Secondly if the work queue becomes empty when calling
439 // WorkQueue::TakeTaskFromWorkQueue (handled there).
440 //
441 // Invokes callbacks created by GetFlagToRequestReloadForEmptyQueue above.
442 empty_queues_to_reload_.RunActiveCallbacks();
443 }
444
MoveReadyDelayedTasksToWorkQueues(LazyNow * lazy_now)445 void SequenceManagerImpl::MoveReadyDelayedTasksToWorkQueues(LazyNow* lazy_now) {
446 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
447 "SequenceManagerImpl::MoveReadyDelayedTasksToWorkQueues");
448
449 EnqueueOrder delayed_task_group_enqueue_order = GetNextSequenceNumber();
450 main_thread_only().wake_up_queue->MoveReadyDelayedTasksToWorkQueues(
451 lazy_now, delayed_task_group_enqueue_order);
452 main_thread_only()
453 .non_waking_wake_up_queue->MoveReadyDelayedTasksToWorkQueues(
454 lazy_now, delayed_task_group_enqueue_order);
455 }
456
OnBeginNestedRunLoop()457 void SequenceManagerImpl::OnBeginNestedRunLoop() {
458 main_thread_only().nesting_depth++;
459 if (main_thread_only().observer)
460 main_thread_only().observer->OnBeginNestedRunLoop();
461 }
462
OnExitNestedRunLoop()463 void SequenceManagerImpl::OnExitNestedRunLoop() {
464 main_thread_only().nesting_depth--;
465 DCHECK_GE(main_thread_only().nesting_depth, 0);
466 if (main_thread_only().nesting_depth == 0) {
467 // While we were nested some non-nestable tasks may have been deferred. We
468 // push them back onto the *front* of their original work queues, that's why
469 // we iterate |non_nestable_task_queue| in LIFO order (we want
470 // |non_nestable_task.front()| to be the last task pushed at the front of
471 // |task_queue|).
472 LazyNow exited_nested_now(main_thread_clock());
473 while (!main_thread_only().non_nestable_task_queue.empty()) {
474 internal::TaskQueueImpl::DeferredNonNestableTask& non_nestable_task =
475 main_thread_only().non_nestable_task_queue.back();
476 if (!non_nestable_task.task.queue_time.is_null()) {
477 // Adjust the deferred tasks' queue time to now so that intentionally
478 // deferred tasks are not unfairly considered as having been stuck in
479 // the queue for a while. Note: this does not affect task ordering as
480 // |enqueue_order| is untouched and deferred tasks will still be pushed
481 // back to the front of the queue.
482 non_nestable_task.task.queue_time = exited_nested_now.Now();
483 }
484 auto* const task_queue = non_nestable_task.task_queue;
485 task_queue->RequeueDeferredNonNestableTask(std::move(non_nestable_task));
486 main_thread_only().non_nestable_task_queue.pop_back();
487 }
488 }
489 if (main_thread_only().observer)
490 main_thread_only().observer->OnExitNestedRunLoop();
491 }
492
ScheduleWork()493 void SequenceManagerImpl::ScheduleWork() {
494 controller_->ScheduleWork();
495 }
496
SetNextWakeUp(LazyNow * lazy_now,std::optional<WakeUp> wake_up)497 void SequenceManagerImpl::SetNextWakeUp(LazyNow* lazy_now,
498 std::optional<WakeUp> wake_up) {
499 auto next_wake_up = AdjustWakeUp(wake_up, lazy_now);
500 if (next_wake_up && next_wake_up->is_immediate()) {
501 ScheduleWork();
502 } else {
503 controller_->SetNextDelayedDoWork(lazy_now, next_wake_up);
504 }
505 }
506
MaybeEmitTaskDetails(perfetto::EventContext & ctx,const SequencedTaskSource::SelectedTask & selected_task) const507 void SequenceManagerImpl::MaybeEmitTaskDetails(
508 perfetto::EventContext& ctx,
509 const SequencedTaskSource::SelectedTask& selected_task) const {
510 #if BUILDFLAG(ENABLE_BASE_TRACING)
511 // Other parameters are included only when "scheduler" category is enabled.
512 const uint8_t* scheduler_category_enabled =
513 TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("scheduler");
514
515 if (!*scheduler_category_enabled)
516 return;
517 auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
518 auto* sequence_manager_task = event->set_sequence_manager_task();
519 sequence_manager_task->set_priority(
520 settings().priority_settings.TaskPriorityToProto(selected_task.priority));
521 sequence_manager_task->set_queue_name(selected_task.task_queue_name);
522
523 #endif // BUILDFLAG(ENABLE_BASE_TRACING)
524 }
525
SetRunTaskSynchronouslyAllowed(bool can_run_tasks_synchronously)526 void SequenceManagerImpl::SetRunTaskSynchronouslyAllowed(
527 bool can_run_tasks_synchronously) {
528 work_tracker_.SetRunTaskSynchronouslyAllowed(can_run_tasks_synchronously);
529 }
530
531 std::optional<SequenceManagerImpl::SelectedTask>
SelectNextTask(LazyNow & lazy_now,SelectTaskOption option)532 SequenceManagerImpl::SelectNextTask(LazyNow& lazy_now,
533 SelectTaskOption option) {
534 std::optional<SelectedTask> selected_task =
535 SelectNextTaskImpl(lazy_now, option);
536
537 if (selected_task.has_value()) {
538 work_tracker_.AssertHasWork();
539 }
540
541 return selected_task;
542 }
543
544 #if DCHECK_IS_ON() && !BUILDFLAG(IS_NACL)
LogTaskDebugInfo(const WorkQueue * selected_work_queue) const545 void SequenceManagerImpl::LogTaskDebugInfo(
546 const WorkQueue* selected_work_queue) const {
547 const Task* task = selected_work_queue->GetFrontTask();
548 switch (settings_.task_execution_logging) {
549 case Settings::TaskLogging::kNone:
550 break;
551
552 case Settings::TaskLogging::kEnabled:
553 LOG(INFO) << "#" << static_cast<uint64_t>(task->enqueue_order()) << " "
554 << selected_work_queue->task_queue()->GetName()
555 << (task->cross_thread_ ? " Run crossthread " : " Run ")
556 << task->posted_from.ToString();
557 break;
558
559 case Settings::TaskLogging::kEnabledWithBacktrace: {
560 std::array<const void*, PendingTask::kTaskBacktraceLength + 1> task_trace;
561 task_trace[0] = task->posted_from.program_counter();
562 ranges::copy(task->task_backtrace, task_trace.begin() + 1);
563 size_t length = 0;
564 while (length < task_trace.size() && task_trace[length])
565 ++length;
566 if (length == 0)
567 break;
568 LOG(INFO) << "#" << static_cast<uint64_t>(task->enqueue_order()) << " "
569 << selected_work_queue->task_queue()->GetName()
570 << (task->cross_thread_ ? " Run crossthread " : " Run ")
571 << debug::StackTrace(base::span(task_trace).first(length));
572 break;
573 }
574
575 case Settings::TaskLogging::kReorderedOnly: {
576 std::vector<const Task*> skipped_tasks;
577 main_thread_only().selector.CollectSkippedOverLowerPriorityTasks(
578 selected_work_queue, &skipped_tasks);
579
580 if (skipped_tasks.empty())
581 break;
582
583 LOG(INFO) << "#" << static_cast<uint64_t>(task->enqueue_order()) << " "
584 << selected_work_queue->task_queue()->GetName()
585 << (task->cross_thread_ ? " Run crossthread " : " Run ")
586 << task->posted_from.ToString();
587
588 for (const Task* skipped_task : skipped_tasks) {
589 LOG(INFO) << "# (skipped over) "
590 << static_cast<uint64_t>(skipped_task->enqueue_order()) << " "
591 << skipped_task->posted_from.ToString();
592 }
593 }
594 }
595 }
596 #endif // DCHECK_IS_ON() && !BUILDFLAG(IS_NACL)
597
598 std::optional<SequenceManagerImpl::SelectedTask>
SelectNextTaskImpl(LazyNow & lazy_now,SelectTaskOption option)599 SequenceManagerImpl::SelectNextTaskImpl(LazyNow& lazy_now,
600 SelectTaskOption option) {
601 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
602 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
603 "SequenceManagerImpl::SelectNextTask");
604
605 ReloadEmptyWorkQueues();
606 MoveReadyDelayedTasksToWorkQueues(&lazy_now);
607
608 // If we sampled now, check if it's time to reclaim memory next time we go
609 // idle.
610 if (lazy_now.has_value() &&
611 lazy_now.Now() >= main_thread_only().next_time_to_reclaim_memory) {
612 main_thread_only().memory_reclaim_scheduled = true;
613 }
614
615 while (true) {
616 internal::WorkQueue* work_queue =
617 main_thread_only().selector.SelectWorkQueueToService(option);
618 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
619 TRACE_DISABLED_BY_DEFAULT("sequence_manager.debug"), "SequenceManager",
620 this,
621 AsValueWithSelectorResultForTracing(work_queue,
622 /* force_verbose */ false));
623
624 if (!work_queue)
625 return std::nullopt;
626
627 // If the head task was canceled, remove it and run the selector again.
628 if (work_queue->RemoveAllCanceledTasksFromFront()) [[unlikely]] {
629 continue;
630 }
631
632 if (work_queue->GetFrontTask()->nestable == Nestable::kNonNestable &&
633 main_thread_only().nesting_depth > 0) [[unlikely]] {
634 // Defer non-nestable work. NOTE these tasks can be arbitrarily delayed so
635 // the additional delay should not be a problem.
636 // Note because we don't delete queues while nested, it's perfectly OK to
637 // store the raw pointer for |queue| here.
638 internal::TaskQueueImpl::DeferredNonNestableTask deferred_task{
639 work_queue->TakeTaskFromWorkQueue(), work_queue->task_queue(),
640 work_queue->queue_type()};
641 main_thread_only().non_nestable_task_queue.push_back(
642 std::move(deferred_task));
643 continue;
644 }
645
646 #if DCHECK_IS_ON() && !BUILDFLAG(IS_NACL)
647 LogTaskDebugInfo(work_queue);
648 #endif // DCHECK_IS_ON() && !BUILDFLAG(IS_NACL)
649
650 main_thread_only().task_execution_stack.emplace_back(
651 work_queue->TakeTaskFromWorkQueue(), work_queue->task_queue(),
652 InitializeTaskTiming(work_queue->task_queue()));
653
654 ExecutingTask& executing_task =
655 *main_thread_only().task_execution_stack.rbegin();
656 NotifyWillProcessTask(&executing_task, &lazy_now);
657
658 // Maybe invalidate the delayed task handle. If already invalidated, then
659 // don't run this task.
660 if (!executing_task.pending_task.WillRunTask()) {
661 executing_task.pending_task.task = DoNothing();
662 }
663
664 return SelectedTask(
665 executing_task.pending_task,
666 executing_task.task_queue->task_execution_trace_logger(),
667 executing_task.priority, executing_task.task_queue_name);
668 }
669 }
670
DidRunTask(LazyNow & lazy_now)671 void SequenceManagerImpl::DidRunTask(LazyNow& lazy_now) {
672 work_tracker_.AssertHasWork();
673
674 ExecutingTask& executing_task =
675 *main_thread_only().task_execution_stack.rbegin();
676
677 NotifyDidProcessTask(&executing_task, &lazy_now);
678 main_thread_only().task_execution_stack.pop_back();
679
680 if (main_thread_only().nesting_depth == 0)
681 CleanUpQueues();
682 }
683
RemoveAllCanceledDelayedTasksFromFront(LazyNow * lazy_now)684 void SequenceManagerImpl::RemoveAllCanceledDelayedTasksFromFront(
685 LazyNow* lazy_now) {
686 main_thread_only().wake_up_queue->RemoveAllCanceledDelayedTasksFromFront(
687 lazy_now);
688 main_thread_only()
689 .non_waking_wake_up_queue->RemoveAllCanceledDelayedTasksFromFront(
690 lazy_now);
691 }
692
GetPendingWakeUp(LazyNow * lazy_now,SelectTaskOption option)693 std::optional<WakeUp> SequenceManagerImpl::GetPendingWakeUp(
694 LazyNow* lazy_now,
695 SelectTaskOption option) {
696 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
697
698 RemoveAllCanceledDelayedTasksFromFront(lazy_now);
699
700 if (main_thread_only().selector.GetHighestPendingPriority(option)) {
701 // If the selector has non-empty queues we trivially know there is immediate
702 // work to be done. However we may want to yield to native work if it is
703 // more important.
704 return WakeUp{};
705 }
706
707 // There may be some incoming immediate work which we haven't accounted for.
708 // NB ReloadEmptyWorkQueues involves a memory barrier, so it's fastest to not
709 // do this always.
710 ReloadEmptyWorkQueues();
711
712 if (main_thread_only().selector.GetHighestPendingPriority(option)) {
713 return WakeUp{};
714 }
715
716 // Otherwise we need to find the shortest delay, if any. NB we don't need to
717 // call MoveReadyDelayedTasksToWorkQueues because it's assumed
718 // DelayTillNextTask will return TimeDelta>() if the delayed task is due to
719 // run now.
720 return AdjustWakeUp(GetNextDelayedWakeUpWithOption(option), lazy_now);
721 }
722
GetNextDelayedWakeUp() const723 std::optional<WakeUp> SequenceManagerImpl::GetNextDelayedWakeUp() const {
724 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
725 return main_thread_only().wake_up_queue->GetNextDelayedWakeUp();
726 }
727
GetNextDelayedWakeUpWithOption(SelectTaskOption option) const728 std::optional<WakeUp> SequenceManagerImpl::GetNextDelayedWakeUpWithOption(
729 SelectTaskOption option) const {
730 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
731
732 if (option == SelectTaskOption::kSkipDelayedTask)
733 return std::nullopt;
734 return GetNextDelayedWakeUp();
735 }
736
AdjustWakeUp(std::optional<WakeUp> wake_up,LazyNow * lazy_now) const737 std::optional<WakeUp> SequenceManagerImpl::AdjustWakeUp(
738 std::optional<WakeUp> wake_up,
739 LazyNow* lazy_now) const {
740 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
741 if (!wake_up)
742 return std::nullopt;
743 // Overdue work needs to be run immediately.
744 if (lazy_now->Now() >= wake_up->earliest_time())
745 return WakeUp{};
746 // If |time_domain| is present, we don't want an actual OS level delayed wake
747 // up scheduled, so pretend we have no more work. This will result in
748 // appearing idle and |time_domain| will decide what to do in
749 // MaybeFastForwardToWakeUp().
750 if (main_thread_only().time_domain)
751 return std::nullopt;
752 return *wake_up;
753 }
754
MaybeAddLeewayToTask(Task & task) const755 void SequenceManagerImpl::MaybeAddLeewayToTask(Task& task) const {
756 if (!main_thread_only().time_domain) {
757 task.leeway = MessagePump::GetLeewayForCurrentThread();
758 }
759 }
760
761 // TODO(crbug.com/40204558): Rename once ExplicitHighResolutionTimerWin
762 // experiment is shipped.
HasPendingHighResolutionTasks()763 bool SequenceManagerImpl::HasPendingHighResolutionTasks() {
764 // Only consider high-res tasks in the |wake_up_queue| (ignore the
765 // |non_waking_wake_up_queue|).
766 #if BUILDFLAG(IS_WIN)
767 if (g_explicit_high_resolution_timer_win) {
768 std::optional<WakeUp> wake_up =
769 main_thread_only().wake_up_queue->GetNextDelayedWakeUp();
770 if (!wake_up)
771 return false;
772 // Under the kExplicitHighResolutionTimerWin experiment, rely on leeway
773 // being larger than the minimum time of a low resolution timer (16ms). This
774 // way, we don't need to activate the high resolution timer for precise
775 // tasks that will run in more than 16ms if there are non precise tasks in
776 // front of them.
777 DCHECK_GE(MessagePump::GetLeewayIgnoringThreadOverride(),
778 Milliseconds(Time::kMinLowResolutionThresholdMs));
779 return wake_up->delay_policy == subtle::DelayPolicy::kPrecise;
780 }
781 #endif // BUILDFLAG(IS_WIN)
782 return main_thread_only().wake_up_queue->has_pending_high_resolution_tasks();
783 }
784
OnBeginWork()785 void SequenceManagerImpl::OnBeginWork() {
786 work_tracker_.OnBeginWork();
787 }
788
OnIdle()789 bool SequenceManagerImpl::OnIdle() {
790 bool have_work_to_do = false;
791 if (main_thread_only().time_domain) {
792 auto wakeup = main_thread_only().wake_up_queue->GetNextDelayedWakeUp();
793 have_work_to_do = main_thread_only().time_domain->MaybeFastForwardToWakeUp(
794 wakeup, controller_->ShouldQuitRunLoopWhenIdle());
795 }
796 if (!have_work_to_do) {
797 MaybeReclaimMemory();
798 main_thread_only().on_next_idle_callbacks.Notify();
799 if (main_thread_only().task_execution_stack.empty()) {
800 work_tracker_.OnIdle();
801 }
802 }
803 return have_work_to_do;
804 }
805
WillRequestReloadImmediateWorkQueue()806 void SequenceManagerImpl::WillRequestReloadImmediateWorkQueue() {
807 work_tracker_.WillRequestReloadImmediateWorkQueue();
808 }
809
TryAcquireSyncWorkAuthorization()810 SyncWorkAuthorization SequenceManagerImpl::TryAcquireSyncWorkAuthorization() {
811 return work_tracker_.TryAcquireSyncWorkAuthorization();
812 }
813
WillQueueTask(Task * pending_task)814 void SequenceManagerImpl::WillQueueTask(Task* pending_task) {
815 controller_->WillQueueTask(pending_task);
816 }
817
InitializeTaskTiming(internal::TaskQueueImpl * task_queue)818 TaskQueue::TaskTiming SequenceManagerImpl::InitializeTaskTiming(
819 internal::TaskQueueImpl* task_queue) {
820 bool records_wall_time =
821 ShouldRecordTaskTiming(task_queue) == TimeRecordingPolicy::DoRecord;
822 bool records_thread_time = records_wall_time && ShouldRecordCPUTimeForTask();
823 return TaskQueue::TaskTiming(records_wall_time, records_thread_time);
824 }
825
ShouldRecordTaskTiming(const internal::TaskQueueImpl * task_queue)826 TimeRecordingPolicy SequenceManagerImpl::ShouldRecordTaskTiming(
827 const internal::TaskQueueImpl* task_queue) {
828 if (task_queue->RequiresTaskTiming())
829 return TimeRecordingPolicy::DoRecord;
830 if (main_thread_only().nesting_depth == 0 &&
831 !main_thread_only().task_time_observers.empty()) {
832 return TimeRecordingPolicy::DoRecord;
833 }
834 return TimeRecordingPolicy::DoNotRecord;
835 }
836
NotifyWillProcessTask(ExecutingTask * executing_task,LazyNow * time_before_task)837 void SequenceManagerImpl::NotifyWillProcessTask(ExecutingTask* executing_task,
838 LazyNow* time_before_task) {
839 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
840 "SequenceManagerImpl::NotifyWillProcessTaskObservers");
841
842 if (g_record_crash_keys.load(std::memory_order_relaxed)) {
843 RecordCrashKeys(executing_task->pending_task);
844 }
845
846 if (executing_task->task_queue->GetQuiescenceMonitored())
847 main_thread_only().task_was_run_on_quiescence_monitored_queue = true;
848
849 TimeRecordingPolicy recording_policy =
850 ShouldRecordTaskTiming(executing_task->task_queue);
851 if (recording_policy == TimeRecordingPolicy::DoRecord)
852 executing_task->task_timing.RecordTaskStart(time_before_task);
853
854 if (!executing_task->task_queue->GetShouldNotifyObservers())
855 return;
856
857 const bool was_blocked_or_low_priority =
858 executing_task->task_queue->WasBlockedOrLowPriority(
859 executing_task->pending_task.enqueue_order());
860
861 {
862 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
863 "SequenceManager.WillProcessTaskObservers");
864 for (auto& observer : main_thread_only().task_observers) {
865 observer.WillProcessTask(executing_task->pending_task,
866 was_blocked_or_low_priority);
867 }
868 }
869
870 {
871 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
872 "SequenceManager.QueueNotifyWillProcessTask");
873 executing_task->task_queue->NotifyWillProcessTask(
874 executing_task->pending_task, was_blocked_or_low_priority);
875 }
876
877 if (recording_policy != TimeRecordingPolicy::DoRecord)
878 return;
879
880 if (main_thread_only().nesting_depth == 0) {
881 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
882 "SequenceManager.WillProcessTaskTimeObservers");
883 for (auto& observer : main_thread_only().task_time_observers)
884 observer.WillProcessTask(executing_task->task_timing.start_time());
885 }
886
887 {
888 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
889 "SequenceManager.QueueOnTaskStarted");
890 executing_task->task_queue->OnTaskStarted(executing_task->pending_task,
891 executing_task->task_timing);
892 }
893 }
894
NotifyDidProcessTask(ExecutingTask * executing_task,LazyNow * time_after_task)895 void SequenceManagerImpl::NotifyDidProcessTask(ExecutingTask* executing_task,
896 LazyNow* time_after_task) {
897 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
898 "SequenceManagerImpl::NotifyDidProcessTaskObservers");
899 if (!executing_task->task_queue->GetShouldNotifyObservers())
900 return;
901
902 TaskQueue::TaskTiming& task_timing = executing_task->task_timing;
903
904 {
905 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
906 "SequenceManager.QueueOnTaskCompleted");
907 if (task_timing.has_wall_time()) {
908 executing_task->task_queue->OnTaskCompleted(
909 executing_task->pending_task, &task_timing, time_after_task);
910 }
911 }
912
913 bool has_valid_start =
914 task_timing.state() != TaskQueue::TaskTiming::State::NotStarted;
915 TimeRecordingPolicy recording_policy =
916 ShouldRecordTaskTiming(executing_task->task_queue);
917 // Record end time ASAP to avoid bias due to the overhead of observers.
918 if (recording_policy == TimeRecordingPolicy::DoRecord && has_valid_start) {
919 task_timing.RecordTaskEnd(time_after_task);
920 }
921
922 if (has_valid_start && task_timing.has_wall_time() &&
923 main_thread_only().nesting_depth == 0) {
924 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
925 "SequenceManager.DidProcessTaskTimeObservers");
926 for (auto& observer : main_thread_only().task_time_observers) {
927 observer.DidProcessTask(task_timing.start_time(), task_timing.end_time());
928 }
929 }
930
931 {
932 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
933 "SequenceManager.DidProcessTaskObservers");
934 for (auto& observer : main_thread_only().task_observers)
935 observer.DidProcessTask(executing_task->pending_task);
936 }
937
938 {
939 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
940 "SequenceManager.QueueNotifyDidProcessTask");
941 executing_task->task_queue->NotifyDidProcessTask(
942 executing_task->pending_task);
943 }
944
945 // TODO(altimin): Move this back to blink.
946 if (task_timing.has_wall_time() &&
947 recording_policy == TimeRecordingPolicy::DoRecord &&
948 task_timing.wall_duration() > kLongTaskTraceEventThreshold &&
949 main_thread_only().nesting_depth == 0) {
950 TRACE_EVENT_INSTANT1("blink", "LongTask", TRACE_EVENT_SCOPE_THREAD,
951 "duration", task_timing.wall_duration().InSecondsF());
952 }
953 }
954
SetWorkBatchSize(int work_batch_size)955 void SequenceManagerImpl::SetWorkBatchSize(int work_batch_size) {
956 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
957 DCHECK_GE(work_batch_size, 1);
958 controller_->SetWorkBatchSize(work_batch_size);
959 }
960
AddTaskObserver(TaskObserver * task_observer)961 void SequenceManagerImpl::AddTaskObserver(TaskObserver* task_observer) {
962 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
963 main_thread_only().task_observers.AddObserver(task_observer);
964 }
965
RemoveTaskObserver(TaskObserver * task_observer)966 void SequenceManagerImpl::RemoveTaskObserver(TaskObserver* task_observer) {
967 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
968 main_thread_only().task_observers.RemoveObserver(task_observer);
969 }
970
AddTaskTimeObserver(TaskTimeObserver * task_time_observer)971 void SequenceManagerImpl::AddTaskTimeObserver(
972 TaskTimeObserver* task_time_observer) {
973 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
974 main_thread_only().task_time_observers.AddObserver(task_time_observer);
975 }
976
RemoveTaskTimeObserver(TaskTimeObserver * task_time_observer)977 void SequenceManagerImpl::RemoveTaskTimeObserver(
978 TaskTimeObserver* task_time_observer) {
979 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
980 main_thread_only().task_time_observers.RemoveObserver(task_time_observer);
981 }
982
GetAndClearSystemIsQuiescentBit()983 bool SequenceManagerImpl::GetAndClearSystemIsQuiescentBit() {
984 bool task_was_run =
985 main_thread_only().task_was_run_on_quiescence_monitored_queue;
986 main_thread_only().task_was_run_on_quiescence_monitored_queue = false;
987 return !task_was_run;
988 }
989
GetNextSequenceNumber()990 EnqueueOrder SequenceManagerImpl::GetNextSequenceNumber() {
991 return enqueue_order_generator_.GenerateNext();
992 }
993
994 std::unique_ptr<trace_event::ConvertableToTraceFormat>
AsValueWithSelectorResultForTracing(internal::WorkQueue * selected_work_queue,bool force_verbose) const995 SequenceManagerImpl::AsValueWithSelectorResultForTracing(
996 internal::WorkQueue* selected_work_queue,
997 bool force_verbose) const {
998 return std::make_unique<TracedBaseValue>(
999 Value(AsValueWithSelectorResult(selected_work_queue, force_verbose)));
1000 }
1001
AsValueWithSelectorResult(internal::WorkQueue * selected_work_queue,bool force_verbose) const1002 Value::Dict SequenceManagerImpl::AsValueWithSelectorResult(
1003 internal::WorkQueue* selected_work_queue,
1004 bool force_verbose) const {
1005 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
1006 TimeTicks now = NowTicks();
1007 Value::Dict state;
1008 Value::List active_queues;
1009 for (internal::TaskQueueImpl* const queue :
1010 main_thread_only().active_queues) {
1011 active_queues.Append(queue->AsValue(now, force_verbose));
1012 }
1013 state.Set("active_queues", std::move(active_queues));
1014 Value::List shutdown_queues;
1015 Value::List queues_to_delete;
1016 for (const auto& pair : main_thread_only().queues_to_delete)
1017 queues_to_delete.Append(pair.first->AsValue(now, force_verbose));
1018 state.Set("queues_to_delete", std::move(queues_to_delete));
1019 state.Set("selector", main_thread_only().selector.AsValue());
1020 if (selected_work_queue) {
1021 state.Set("selected_queue", selected_work_queue->task_queue()->GetName());
1022 state.Set("work_queue_name", selected_work_queue->name());
1023 }
1024 state.Set("time_domain", main_thread_only().time_domain
1025 ? main_thread_only().time_domain->AsValue()
1026 : Value::Dict());
1027 state.Set("wake_up_queue", main_thread_only().wake_up_queue->AsValue(now));
1028 state.Set("non_waking_wake_up_queue",
1029 main_thread_only().non_waking_wake_up_queue->AsValue(now));
1030 return state;
1031 }
1032
OnTaskQueueEnabled(internal::TaskQueueImpl * queue)1033 void SequenceManagerImpl::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
1034 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
1035 DCHECK(queue->IsQueueEnabled());
1036 // Only schedule DoWork if there's something to do.
1037 if (queue->HasTaskToRunImmediatelyOrReadyDelayedTask() &&
1038 !queue->BlockedByFence())
1039 ScheduleWork();
1040 }
1041
OnWorkAvailable()1042 void SequenceManagerImpl::OnWorkAvailable() {
1043 work_tracker_.OnBeginWork();
1044 }
1045
MaybeReclaimMemory()1046 void SequenceManagerImpl::MaybeReclaimMemory() {
1047 if (!main_thread_only().memory_reclaim_scheduled)
1048 return;
1049
1050 TRACE_EVENT0("sequence_manager", "SequenceManagerImpl::MaybeReclaimMemory");
1051 ReclaimMemory();
1052
1053 // To avoid performance regressions we only want to do this every so often.
1054 main_thread_only().next_time_to_reclaim_memory =
1055 NowTicks() + kReclaimMemoryInterval;
1056 main_thread_only().memory_reclaim_scheduled = false;
1057 }
1058
ReclaimMemory()1059 void SequenceManagerImpl::ReclaimMemory() {
1060 LazyNow lazy_now(main_thread_clock());
1061 for (auto it = main_thread_only().active_queues.begin();
1062 it != main_thread_only().active_queues.end();) {
1063 auto* const queue = *it++;
1064 ReclaimMemoryFromQueue(queue, &lazy_now);
1065 }
1066 }
1067
CleanUpQueues()1068 void SequenceManagerImpl::CleanUpQueues() {
1069 main_thread_only().queues_to_delete.clear();
1070 }
1071
GetWeakPtr()1072 WeakPtr<SequenceManagerImpl> SequenceManagerImpl::GetWeakPtr() {
1073 return weak_factory_.GetWeakPtr();
1074 }
1075
SetDefaultTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner)1076 void SequenceManagerImpl::SetDefaultTaskRunner(
1077 scoped_refptr<SingleThreadTaskRunner> task_runner) {
1078 controller_->SetDefaultTaskRunner(task_runner);
1079 }
1080
GetTickClock() const1081 const TickClock* SequenceManagerImpl::GetTickClock() const {
1082 return any_thread_clock();
1083 }
1084
NowTicks() const1085 TimeTicks SequenceManagerImpl::NowTicks() const {
1086 return any_thread_clock()->NowTicks();
1087 }
1088
ShouldRecordCPUTimeForTask()1089 bool SequenceManagerImpl::ShouldRecordCPUTimeForTask() {
1090 DCHECK(ThreadTicks::IsSupported() ||
1091 !metric_recording_settings_.records_cpu_time_for_some_tasks());
1092 return metric_recording_settings_.records_cpu_time_for_some_tasks() &&
1093 main_thread_only().metrics_subsampler->ShouldSample(
1094 metric_recording_settings_
1095 .task_sampling_rate_for_recording_cpu_time);
1096 }
1097
1098 const SequenceManager::MetricRecordingSettings&
GetMetricRecordingSettings() const1099 SequenceManagerImpl::GetMetricRecordingSettings() const {
1100 return metric_recording_settings_;
1101 }
1102
SetTaskExecutionAllowedInNativeNestedLoop(bool allowed)1103 void SequenceManagerImpl::SetTaskExecutionAllowedInNativeNestedLoop(
1104 bool allowed) {
1105 controller_->SetTaskExecutionAllowedInNativeNestedLoop(allowed);
1106 }
1107
IsTaskExecutionAllowedInNativeNestedLoop() const1108 bool SequenceManagerImpl::IsTaskExecutionAllowedInNativeNestedLoop() const {
1109 return controller_->IsTaskExecutionAllowed();
1110 }
1111
1112 #if BUILDFLAG(IS_IOS)
AttachToMessagePump()1113 void SequenceManagerImpl::AttachToMessagePump() {
1114 return controller_->AttachToMessagePump();
1115 }
1116 #endif
1117
IsIdleForTesting()1118 bool SequenceManagerImpl::IsIdleForTesting() {
1119 ReloadEmptyWorkQueues();
1120
1121 // Make sure that canceled tasks don't affect the return value.
1122 for (internal::TaskQueueImpl* queue : main_thread_only().active_queues) {
1123 queue->delayed_work_queue()->RemoveAllCanceledTasksFromFront();
1124 queue->immediate_work_queue()->RemoveAllCanceledTasksFromFront();
1125 }
1126
1127 return !main_thread_only().selector.GetHighestPendingPriority().has_value();
1128 }
1129
EnableMessagePumpTimeKeeperMetrics(const char * thread_name,bool wall_time_based_metrics_enabled_for_testing)1130 void SequenceManagerImpl::EnableMessagePumpTimeKeeperMetrics(
1131 const char* thread_name,
1132 bool wall_time_based_metrics_enabled_for_testing) {
1133 controller_->EnableMessagePumpTimeKeeperMetrics(
1134 thread_name, wall_time_based_metrics_enabled_for_testing);
1135 }
1136
GetPendingTaskCountForTesting() const1137 size_t SequenceManagerImpl::GetPendingTaskCountForTesting() const {
1138 size_t total = 0;
1139 for (internal::TaskQueueImpl* task_queue : main_thread_only().active_queues) {
1140 total += task_queue->GetNumberOfPendingTasks();
1141 }
1142 return total;
1143 }
1144
CreateTaskQueue(const TaskQueue::Spec & spec)1145 TaskQueue::Handle SequenceManagerImpl::CreateTaskQueue(
1146 const TaskQueue::Spec& spec) {
1147 return TaskQueue::Handle(CreateTaskQueueImpl(spec));
1148 }
1149
DescribeAllPendingTasks() const1150 std::string SequenceManagerImpl::DescribeAllPendingTasks() const {
1151 Value::Dict value =
1152 AsValueWithSelectorResult(nullptr, /* force_verbose */ true);
1153 std::string result;
1154 JSONWriter::Write(value, &result);
1155 return result;
1156 }
1157
PrioritizeYieldingToNative(base::TimeTicks prioritize_until)1158 void SequenceManagerImpl::PrioritizeYieldingToNative(
1159 base::TimeTicks prioritize_until) {
1160 controller_->PrioritizeYieldingToNative(prioritize_until);
1161 }
1162
AddDestructionObserver(CurrentThread::DestructionObserver * destruction_observer)1163 void SequenceManagerImpl::AddDestructionObserver(
1164 CurrentThread::DestructionObserver* destruction_observer) {
1165 main_thread_only().destruction_observers.AddObserver(destruction_observer);
1166 }
1167
RemoveDestructionObserver(CurrentThread::DestructionObserver * destruction_observer)1168 void SequenceManagerImpl::RemoveDestructionObserver(
1169 CurrentThread::DestructionObserver* destruction_observer) {
1170 main_thread_only().destruction_observers.RemoveObserver(destruction_observer);
1171 }
1172
RegisterOnNextIdleCallback(OnceClosure on_next_idle_callback)1173 CallbackListSubscription SequenceManagerImpl::RegisterOnNextIdleCallback(
1174 OnceClosure on_next_idle_callback) {
1175 return main_thread_only().on_next_idle_callbacks.Add(
1176 std::move(on_next_idle_callback));
1177 }
1178
SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner)1179 void SequenceManagerImpl::SetTaskRunner(
1180 scoped_refptr<SingleThreadTaskRunner> task_runner) {
1181 controller_->SetDefaultTaskRunner(task_runner);
1182 }
1183
GetTaskRunner()1184 scoped_refptr<SingleThreadTaskRunner> SequenceManagerImpl::GetTaskRunner() {
1185 return controller_->GetDefaultTaskRunner();
1186 }
1187
IsBoundToCurrentThread() const1188 bool SequenceManagerImpl::IsBoundToCurrentThread() const {
1189 return associated_thread_->IsBoundToCurrentThread();
1190 }
1191
GetMessagePump() const1192 MessagePump* SequenceManagerImpl::GetMessagePump() const {
1193 return controller_->GetBoundMessagePump();
1194 }
1195
IsType(MessagePumpType type) const1196 bool SequenceManagerImpl::IsType(MessagePumpType type) const {
1197 return settings_.message_loop_type == type;
1198 }
1199
EnableCrashKeys(const char * async_stack_crash_key)1200 void SequenceManagerImpl::EnableCrashKeys(const char* async_stack_crash_key) {
1201 DCHECK(!main_thread_only().async_stack_crash_key);
1202 #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
1203 main_thread_only().async_stack_crash_key = debug::AllocateCrashKeyString(
1204 async_stack_crash_key, debug::CrashKeySize::Size64);
1205 static_assert(sizeof(main_thread_only().async_stack_buffer) ==
1206 static_cast<size_t>(debug::CrashKeySize::Size64),
1207 "Async stack buffer size must match crash key size.");
1208 #endif // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
1209 }
1210
RecordCrashKeys(const PendingTask & pending_task)1211 void SequenceManagerImpl::RecordCrashKeys(const PendingTask& pending_task) {
1212 #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
1213 // SetCrashKeyString is a no-op even if the crash key is null, but we'd still
1214 // have construct the std::string_view that is passed in.
1215 if (!main_thread_only().async_stack_crash_key)
1216 return;
1217
1218 // Write the async stack trace onto a crash key as whitespace-delimited hex
1219 // addresses. These will be symbolized by the crash reporting system. With
1220 // 63 characters we can fit the address of the task that posted the current
1221 // task and its predecessor. Avoid HexEncode since it incurs a memory
1222 // allocation and snprintf because it's about 3.5x slower on Android this
1223 // this.
1224 //
1225 // See
1226 // https://chromium.googlesource.com/chromium/src/+/main/docs/debugging_with_crash_keys.md
1227 // for instructions for symbolizing these crash keys.
1228 //
1229 // TODO(skyostil): Find a way to extract the destination function address
1230 // from the task.
1231 size_t max_size = main_thread_only().async_stack_buffer.size();
1232 char* const buffer = &main_thread_only().async_stack_buffer[0];
1233 char* const buffer_end = &buffer[max_size - 1];
1234 char* pos = buffer_end;
1235 // Leave space for the NUL terminator.
1236 pos = PrependHexAddress(pos - 1, pending_task.task_backtrace[0]);
1237 *(--pos) = ' ';
1238 pos = PrependHexAddress(pos - 1, pending_task.posted_from.program_counter());
1239 DCHECK_GE(pos, buffer);
1240 debug::SetCrashKeyString(
1241 main_thread_only().async_stack_crash_key,
1242 std::string_view(pos, static_cast<size_t>(buffer_end - pos)));
1243 #endif // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID)
1244 }
1245
currently_executing_task_queue() const1246 internal::TaskQueueImpl* SequenceManagerImpl::currently_executing_task_queue()
1247 const {
1248 if (main_thread_only().task_execution_stack.empty())
1249 return nullptr;
1250 return main_thread_only().task_execution_stack.rbegin()->task_queue;
1251 }
1252
GetPriorityCount() const1253 TaskQueue::QueuePriority SequenceManagerImpl::GetPriorityCount() const {
1254 return settings().priority_settings.priority_count();
1255 }
1256
1257 constexpr TimeDelta SequenceManagerImpl::kReclaimMemoryInterval;
1258
1259 } // namespace internal
1260 } // namespace sequence_manager
1261 } // namespace base
1262