• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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