1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/task/sequence_manager/sequence_manager_impl.h"
6
7 #include <queue>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/bit_cast.h"
12 #include "base/compiler_specific.h"
13 #include "base/debug/crash_logging.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/rand_util.h"
17 #include "base/task/sequence_manager/real_time_domain.h"
18 #include "base/task/sequence_manager/task_time_observer.h"
19 #include "base/task/sequence_manager/thread_controller_impl.h"
20 #include "base/task/sequence_manager/work_queue.h"
21 #include "base/task/sequence_manager/work_queue_sets.h"
22 #include "base/time/default_tick_clock.h"
23 #include "base/time/tick_clock.h"
24 #include "base/trace_event/trace_event.h"
25 #include "build/build_config.h"
26
27 namespace base {
28 namespace sequence_manager {
29
CreateSequenceManagerOnCurrentThread()30 std::unique_ptr<SequenceManager> CreateSequenceManagerOnCurrentThread() {
31 return internal::SequenceManagerImpl::CreateOnCurrentThread();
32 }
33
34 namespace internal {
35
36 namespace {
37
38 constexpr base::TimeDelta kLongTaskTraceEventThreshold =
39 base::TimeDelta::FromMilliseconds(50);
40 // Proportion of tasks which will record thread time for metrics.
41 const double kTaskSamplingRateForRecordingCPUTime = 0.01;
42 // Proprortion of SequenceManagers which will record thread time for each task,
43 // enabling advanced metrics.
44 const double kThreadSamplingRateForRecordingCPUTime = 0.0001;
45
46 // Magic value to protect against memory corruption and bail out
47 // early when detected.
48 constexpr int kMemoryCorruptionSentinelValue = 0xdeadbeef;
49
SweepCanceledDelayedTasksInQueue(internal::TaskQueueImpl * queue,std::map<TimeDomain *,TimeTicks> * time_domain_now)50 void SweepCanceledDelayedTasksInQueue(
51 internal::TaskQueueImpl* queue,
52 std::map<TimeDomain*, TimeTicks>* time_domain_now) {
53 TimeDomain* time_domain = queue->GetTimeDomain();
54 if (time_domain_now->find(time_domain) == time_domain_now->end())
55 time_domain_now->insert(std::make_pair(time_domain, time_domain->Now()));
56 queue->SweepCanceledDelayedTasks(time_domain_now->at(time_domain));
57 }
58
InitializeMetricRecordingSettings()59 SequenceManager::MetricRecordingSettings InitializeMetricRecordingSettings() {
60 bool cpu_time_recording_always_on =
61 base::RandDouble() < kThreadSamplingRateForRecordingCPUTime;
62 return SequenceManager::MetricRecordingSettings(
63 cpu_time_recording_always_on, kTaskSamplingRateForRecordingCPUTime);
64 }
65
66 } // namespace
67
SequenceManagerImpl(std::unique_ptr<internal::ThreadController> controller)68 SequenceManagerImpl::SequenceManagerImpl(
69 std::unique_ptr<internal::ThreadController> controller)
70 : graceful_shutdown_helper_(new internal::GracefulQueueShutdownHelper()),
71 controller_(std::move(controller)),
72 metric_recording_settings_(InitializeMetricRecordingSettings()),
73 memory_corruption_sentinel_(kMemoryCorruptionSentinelValue),
74 weak_factory_(this) {
75 // TODO(altimin): Create a sequence checker here.
76 DCHECK(controller_->RunsTasksInCurrentSequence());
77
78 TRACE_EVENT_WARMUP_CATEGORY("sequence_manager");
79 TRACE_EVENT_WARMUP_CATEGORY(TRACE_DISABLED_BY_DEFAULT("sequence_manager"));
80 TRACE_EVENT_WARMUP_CATEGORY(
81 TRACE_DISABLED_BY_DEFAULT("sequence_manager.debug"));
82 TRACE_EVENT_WARMUP_CATEGORY(
83 TRACE_DISABLED_BY_DEFAULT("sequence_manager.verbose_snapshots"));
84
85 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
86 TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "SequenceManager", this);
87 main_thread_only().selector.SetTaskQueueSelectorObserver(this);
88
89 RegisterTimeDomain(main_thread_only().real_time_domain.get());
90
91 controller_->SetSequencedTaskSource(this);
92 controller_->AddNestingObserver(this);
93 }
94
~SequenceManagerImpl()95 SequenceManagerImpl::~SequenceManagerImpl() {
96 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
97 TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "SequenceManager", this);
98
99 // TODO(altimin): restore default task runner automatically when
100 // ThreadController is destroyed.
101 controller_->RestoreDefaultTaskRunner();
102
103 for (internal::TaskQueueImpl* queue : main_thread_only().active_queues) {
104 main_thread_only().selector.RemoveQueue(queue);
105 queue->UnregisterTaskQueue();
106 }
107
108 main_thread_only().active_queues.clear();
109 main_thread_only().queues_to_gracefully_shutdown.clear();
110
111 graceful_shutdown_helper_->OnSequenceManagerDeleted();
112
113 main_thread_only().selector.SetTaskQueueSelectorObserver(nullptr);
114 controller_->RemoveNestingObserver(this);
115 }
116
117 SequenceManagerImpl::AnyThread::AnyThread() = default;
118
119 SequenceManagerImpl::AnyThread::~AnyThread() = default;
120
MainThreadOnly()121 SequenceManagerImpl::MainThreadOnly::MainThreadOnly()
122 : random_generator(RandUint64()),
123 uniform_distribution(0.0, 1.0),
124 real_time_domain(new internal::RealTimeDomain()) {}
125
126 SequenceManagerImpl::MainThreadOnly::~MainThreadOnly() = default;
127
128 // static
129 std::unique_ptr<SequenceManagerImpl>
CreateOnCurrentThread()130 SequenceManagerImpl::CreateOnCurrentThread() {
131 return WrapUnique(
132 new SequenceManagerImpl(internal::ThreadControllerImpl::Create(
133 MessageLoop::current(), DefaultTickClock::GetInstance())));
134 }
135
RegisterTimeDomain(TimeDomain * time_domain)136 void SequenceManagerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
137 main_thread_only().time_domains.insert(time_domain);
138 time_domain->OnRegisterWithSequenceManager(this);
139 }
140
UnregisterTimeDomain(TimeDomain * time_domain)141 void SequenceManagerImpl::UnregisterTimeDomain(TimeDomain* time_domain) {
142 main_thread_only().time_domains.erase(time_domain);
143 }
144
GetRealTimeDomain() const145 TimeDomain* SequenceManagerImpl::GetRealTimeDomain() const {
146 return main_thread_only().real_time_domain.get();
147 }
148
149 std::unique_ptr<internal::TaskQueueImpl>
CreateTaskQueueImpl(const TaskQueue::Spec & spec)150 SequenceManagerImpl::CreateTaskQueueImpl(const TaskQueue::Spec& spec) {
151 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
152 TimeDomain* time_domain = spec.time_domain
153 ? spec.time_domain
154 : main_thread_only().real_time_domain.get();
155 DCHECK(main_thread_only().time_domains.find(time_domain) !=
156 main_thread_only().time_domains.end());
157 std::unique_ptr<internal::TaskQueueImpl> task_queue =
158 std::make_unique<internal::TaskQueueImpl>(this, time_domain, spec);
159 main_thread_only().active_queues.insert(task_queue.get());
160 main_thread_only().selector.AddQueue(task_queue.get());
161 return task_queue;
162 }
163
SetObserver(Observer * observer)164 void SequenceManagerImpl::SetObserver(Observer* observer) {
165 main_thread_only().observer = observer;
166 }
167
AddToIncomingImmediateWorkList(internal::TaskQueueImpl * task_queue,internal::EnqueueOrder enqueue_order)168 bool SequenceManagerImpl::AddToIncomingImmediateWorkList(
169 internal::TaskQueueImpl* task_queue,
170 internal::EnqueueOrder enqueue_order) {
171 AutoLock lock(any_thread_lock_);
172 // Check if |task_queue| is already in the linked list.
173 if (task_queue->immediate_work_list_storage()->queue)
174 return false;
175
176 // Insert into the linked list.
177 task_queue->immediate_work_list_storage()->queue = task_queue;
178 task_queue->immediate_work_list_storage()->order = enqueue_order;
179 task_queue->immediate_work_list_storage()->next =
180 any_thread().incoming_immediate_work_list;
181 any_thread().incoming_immediate_work_list =
182 task_queue->immediate_work_list_storage();
183 return true;
184 }
185
RemoveFromIncomingImmediateWorkList(internal::TaskQueueImpl * task_queue)186 void SequenceManagerImpl::RemoveFromIncomingImmediateWorkList(
187 internal::TaskQueueImpl* task_queue) {
188 AutoLock lock(any_thread_lock_);
189 internal::IncomingImmediateWorkList** prev =
190 &any_thread().incoming_immediate_work_list;
191 while (*prev) {
192 if ((*prev)->queue == task_queue) {
193 *prev = (*prev)->next;
194 break;
195 }
196 prev = &(*prev)->next;
197 }
198
199 task_queue->immediate_work_list_storage()->next = nullptr;
200 task_queue->immediate_work_list_storage()->queue = nullptr;
201 }
202
UnregisterTaskQueueImpl(std::unique_ptr<internal::TaskQueueImpl> task_queue)203 void SequenceManagerImpl::UnregisterTaskQueueImpl(
204 std::unique_ptr<internal::TaskQueueImpl> task_queue) {
205 TRACE_EVENT1("sequence_manager", "SequenceManagerImpl::UnregisterTaskQueue",
206 "queue_name", task_queue->GetName());
207 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
208
209 main_thread_only().selector.RemoveQueue(task_queue.get());
210
211 // After UnregisterTaskQueue returns no new tasks can be posted.
212 // It's important to call it first to avoid race condition between removing
213 // the task queue from various lists here and adding it to the same lists
214 // when posting a task.
215 task_queue->UnregisterTaskQueue();
216
217 // Remove |task_queue| from the linked list if present.
218 // This is O(n). We assume this will be a relatively infrequent operation.
219 RemoveFromIncomingImmediateWorkList(task_queue.get());
220
221 // Add |task_queue| to |main_thread_only().queues_to_delete| so we can prevent
222 // it from being freed while any of our structures hold hold a raw pointer to
223 // it.
224 main_thread_only().active_queues.erase(task_queue.get());
225 main_thread_only().queues_to_delete[task_queue.get()] = std::move(task_queue);
226 }
227
ReloadEmptyWorkQueues()228 void SequenceManagerImpl::ReloadEmptyWorkQueues() {
229 // There are two cases where a queue needs reloading. First, it might be
230 // completely empty and we've just posted a task (this method handles that
231 // case). Secondly if the work queue becomes empty in when calling
232 // WorkQueue::TakeTaskFromWorkQueue (handled there).
233 for (internal::TaskQueueImpl* queue : main_thread_only().queues_to_reload) {
234 queue->ReloadImmediateWorkQueueIfEmpty();
235 }
236 }
237
WakeUpReadyDelayedQueues(LazyNow * lazy_now)238 void SequenceManagerImpl::WakeUpReadyDelayedQueues(LazyNow* lazy_now) {
239 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
240 "SequenceManagerImpl::WakeUpReadyDelayedQueues");
241
242 for (TimeDomain* time_domain : main_thread_only().time_domains) {
243 if (time_domain == main_thread_only().real_time_domain.get()) {
244 time_domain->WakeUpReadyDelayedQueues(lazy_now);
245 } else {
246 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow();
247 time_domain->WakeUpReadyDelayedQueues(&time_domain_lazy_now);
248 }
249 }
250 }
251
OnBeginNestedRunLoop()252 void SequenceManagerImpl::OnBeginNestedRunLoop() {
253 main_thread_only().nesting_depth++;
254 if (main_thread_only().observer)
255 main_thread_only().observer->OnBeginNestedRunLoop();
256 }
257
OnExitNestedRunLoop()258 void SequenceManagerImpl::OnExitNestedRunLoop() {
259 main_thread_only().nesting_depth--;
260 DCHECK_GE(main_thread_only().nesting_depth, 0);
261 if (main_thread_only().nesting_depth == 0) {
262 // While we were nested some non-nestable tasks may have been deferred.
263 // We push them back onto the *front* of their original work queues,
264 // that's why we iterate |non_nestable_task_queue| in FIFO order.
265 while (!main_thread_only().non_nestable_task_queue.empty()) {
266 internal::TaskQueueImpl::DeferredNonNestableTask& non_nestable_task =
267 main_thread_only().non_nestable_task_queue.back();
268 non_nestable_task.task_queue->RequeueDeferredNonNestableTask(
269 std::move(non_nestable_task));
270 main_thread_only().non_nestable_task_queue.pop_back();
271 }
272 }
273 if (main_thread_only().observer)
274 main_thread_only().observer->OnExitNestedRunLoop();
275 }
276
OnQueueHasIncomingImmediateWork(internal::TaskQueueImpl * queue,internal::EnqueueOrder enqueue_order,bool queue_is_blocked)277 void SequenceManagerImpl::OnQueueHasIncomingImmediateWork(
278 internal::TaskQueueImpl* queue,
279 internal::EnqueueOrder enqueue_order,
280 bool queue_is_blocked) {
281 if (AddToIncomingImmediateWorkList(queue, enqueue_order) && !queue_is_blocked)
282 controller_->ScheduleWork();
283 }
284
MaybeScheduleImmediateWork(const Location & from_here)285 void SequenceManagerImpl::MaybeScheduleImmediateWork(
286 const Location& from_here) {
287 controller_->ScheduleWork();
288 }
289
SetNextDelayedDoWork(LazyNow * lazy_now,TimeTicks run_time)290 void SequenceManagerImpl::SetNextDelayedDoWork(LazyNow* lazy_now,
291 TimeTicks run_time) {
292 controller_->SetNextDelayedDoWork(lazy_now, run_time);
293 }
294
TakeTask()295 Optional<PendingTask> SequenceManagerImpl::TakeTask() {
296 CHECK(Validate());
297
298 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
299 TRACE_EVENT0("sequence_manager", "SequenceManagerImpl::TakeTask");
300
301 {
302 AutoLock lock(any_thread_lock_);
303 main_thread_only().queues_to_reload.clear();
304
305 for (internal::IncomingImmediateWorkList* iter =
306 any_thread().incoming_immediate_work_list;
307 iter; iter = iter->next) {
308 main_thread_only().queues_to_reload.push_back(iter->queue);
309 iter->queue = nullptr;
310 }
311
312 any_thread().incoming_immediate_work_list = nullptr;
313 }
314
315 // It's important we call ReloadEmptyWorkQueues out side of the lock to
316 // avoid a lock order inversion.
317 ReloadEmptyWorkQueues();
318 LazyNow lazy_now(controller_->GetClock());
319 WakeUpReadyDelayedQueues(&lazy_now);
320
321 while (true) {
322 internal::WorkQueue* work_queue = nullptr;
323 bool should_run =
324 main_thread_only().selector.SelectWorkQueueToService(&work_queue);
325 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
326 TRACE_DISABLED_BY_DEFAULT("sequence_manager.debug"), "SequenceManager",
327 this, AsValueWithSelectorResult(should_run, work_queue));
328
329 if (!should_run)
330 return nullopt;
331
332 // If the head task was canceled, remove it and run the selector again.
333 if (work_queue->RemoveAllCanceledTasksFromFront())
334 continue;
335
336 if (work_queue->GetFrontTask()->nestable == Nestable::kNonNestable &&
337 main_thread_only().nesting_depth > 0) {
338 // Defer non-nestable work. NOTE these tasks can be arbitrarily delayed so
339 // the additional delay should not be a problem.
340 // Note because we don't delete queues while nested, it's perfectly OK to
341 // store the raw pointer for |queue| here.
342 internal::TaskQueueImpl::DeferredNonNestableTask deferred_task{
343 work_queue->TakeTaskFromWorkQueue(), work_queue->task_queue(),
344 work_queue->queue_type()};
345 main_thread_only().non_nestable_task_queue.push_back(
346 std::move(deferred_task));
347 continue;
348 }
349
350 main_thread_only().task_execution_stack.emplace_back(
351 work_queue->TakeTaskFromWorkQueue(), work_queue->task_queue(),
352 InitializeTaskTiming(work_queue->task_queue()));
353
354 UMA_HISTOGRAM_COUNTS_1000("TaskQueueManager.ActiveQueuesCount",
355 main_thread_only().active_queues.size());
356
357 ExecutingTask& executing_task =
358 *main_thread_only().task_execution_stack.rbegin();
359 NotifyWillProcessTask(&executing_task, &lazy_now);
360 return std::move(executing_task.pending_task);
361 }
362 }
363
DidRunTask()364 void SequenceManagerImpl::DidRunTask() {
365 LazyNow lazy_now(controller_->GetClock());
366 ExecutingTask& executing_task =
367 *main_thread_only().task_execution_stack.rbegin();
368 NotifyDidProcessTask(&executing_task, &lazy_now);
369 main_thread_only().task_execution_stack.pop_back();
370
371 if (main_thread_only().nesting_depth == 0)
372 CleanUpQueues();
373 }
374
DelayTillNextTask(LazyNow * lazy_now)375 TimeDelta SequenceManagerImpl::DelayTillNextTask(LazyNow* lazy_now) {
376 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
377
378 // If the selector has non-empty queues we trivially know there is immediate
379 // work to be done.
380 if (!main_thread_only().selector.AllEnabledWorkQueuesAreEmpty())
381 return TimeDelta();
382
383 // Its possible the selectors state is dirty because ReloadEmptyWorkQueues
384 // hasn't been called yet. This check catches the case of fresh incoming work.
385 {
386 AutoLock lock(any_thread_lock_);
387 for (const internal::IncomingImmediateWorkList* iter =
388 any_thread().incoming_immediate_work_list;
389 iter; iter = iter->next) {
390 if (iter->queue->CouldTaskRun(iter->order))
391 return TimeDelta();
392 }
393 }
394
395 // Otherwise we need to find the shortest delay, if any. NB we don't need to
396 // call WakeUpReadyDelayedQueues because it's assumed DelayTillNextTask will
397 // return TimeDelta>() if the delayed task is due to run now.
398 TimeDelta delay_till_next_task = TimeDelta::Max();
399 for (TimeDomain* time_domain : main_thread_only().time_domains) {
400 Optional<TimeDelta> delay = time_domain->DelayTillNextTask(lazy_now);
401 if (!delay)
402 continue;
403
404 if (*delay < delay_till_next_task)
405 delay_till_next_task = *delay;
406 }
407 return delay_till_next_task;
408 }
409
WillQueueTask(internal::TaskQueueImpl::Task * pending_task)410 void SequenceManagerImpl::WillQueueTask(
411 internal::TaskQueueImpl::Task* pending_task) {
412 controller_->WillQueueTask(pending_task);
413 }
414
InitializeTaskTiming(internal::TaskQueueImpl * task_queue)415 TaskQueue::TaskTiming SequenceManagerImpl::InitializeTaskTiming(
416 internal::TaskQueueImpl* task_queue) {
417 bool records_wall_time =
418 (task_queue->GetShouldNotifyObservers() &&
419 main_thread_only().task_time_observers.might_have_observers()) ||
420 task_queue->RequiresTaskTiming();
421 bool records_thread_time = records_wall_time && ShouldRecordCPUTimeForTask();
422 return TaskQueue::TaskTiming(records_wall_time, records_thread_time);
423 }
424
NotifyWillProcessTask(ExecutingTask * executing_task,LazyNow * time_before_task)425 void SequenceManagerImpl::NotifyWillProcessTask(ExecutingTask* executing_task,
426 LazyNow* time_before_task) {
427 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
428 "SequenceManagerImpl::NotifyWillProcessTaskObservers");
429 if (executing_task->task_queue->GetQuiescenceMonitored())
430 main_thread_only().task_was_run_on_quiescence_monitored_queue = true;
431
432 #if !defined(OS_NACL)
433 debug::SetCrashKeyString(
434 main_thread_only().file_name_crash_key,
435 executing_task->pending_task.posted_from.file_name());
436 debug::SetCrashKeyString(
437 main_thread_only().function_name_crash_key,
438 executing_task->pending_task.posted_from.function_name());
439 #endif // OS_NACL
440
441 executing_task->task_timing.RecordTaskStart(time_before_task);
442
443 if (!executing_task->task_queue->GetShouldNotifyObservers())
444 return;
445
446 {
447 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
448 "SequenceManager.WillProcessTaskObservers");
449 for (auto& observer : main_thread_only().task_observers)
450 observer.WillProcessTask(executing_task->pending_task);
451 }
452
453 {
454 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
455 "SequenceManager.QueueNotifyWillProcessTask");
456 executing_task->task_queue->NotifyWillProcessTask(
457 executing_task->pending_task);
458 }
459
460 bool notify_time_observers =
461 main_thread_only().task_time_observers.might_have_observers() ||
462 executing_task->task_queue->RequiresTaskTiming();
463
464 if (!notify_time_observers)
465 return;
466
467 if (main_thread_only().nesting_depth == 0) {
468 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
469 "SequenceManager.WillProcessTaskTimeObservers");
470 for (auto& observer : main_thread_only().task_time_observers)
471 observer.WillProcessTask(executing_task->task_timing.start_time());
472 }
473
474 {
475 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
476 "SequenceManager.QueueOnTaskStarted");
477 executing_task->task_queue->OnTaskStarted(executing_task->pending_task,
478 executing_task->task_timing);
479 }
480 }
481
NotifyDidProcessTask(ExecutingTask * executing_task,LazyNow * time_after_task)482 void SequenceManagerImpl::NotifyDidProcessTask(ExecutingTask* executing_task,
483 LazyNow* time_after_task) {
484 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
485 "SequenceManagerImpl::NotifyDidProcessTaskObservers");
486
487 executing_task->task_timing.RecordTaskEnd(time_after_task);
488
489 const TaskQueue::TaskTiming& task_timing = executing_task->task_timing;
490
491 if (!executing_task->task_queue->GetShouldNotifyObservers())
492 return;
493
494 if (task_timing.has_wall_time() && main_thread_only().nesting_depth == 0) {
495 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
496 "SequenceManager.DidProcessTaskTimeObservers");
497 for (auto& observer : main_thread_only().task_time_observers) {
498 observer.DidProcessTask(task_timing.start_time(), task_timing.end_time());
499 }
500 }
501
502 {
503 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
504 "SequenceManager.DidProcessTaskObservers");
505 for (auto& observer : main_thread_only().task_observers)
506 observer.DidProcessTask(executing_task->pending_task);
507 }
508
509 {
510 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
511 "SequenceManager.QueueNotifyDidProcessTask");
512 executing_task->task_queue->NotifyDidProcessTask(
513 executing_task->pending_task);
514 }
515
516 {
517 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
518 "SequenceManager.QueueOnTaskCompleted");
519 if (task_timing.has_wall_time())
520 executing_task->task_queue->OnTaskCompleted(executing_task->pending_task,
521 task_timing);
522 }
523
524 // TODO(altimin): Move this back to blink.
525 if (task_timing.has_wall_time() &&
526 task_timing.wall_duration() > kLongTaskTraceEventThreshold &&
527 main_thread_only().nesting_depth == 0) {
528 TRACE_EVENT_INSTANT1("blink", "LongTask", TRACE_EVENT_SCOPE_THREAD,
529 "duration", task_timing.wall_duration().InSecondsF());
530 }
531 }
532
SetWorkBatchSize(int work_batch_size)533 void SequenceManagerImpl::SetWorkBatchSize(int work_batch_size) {
534 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
535 DCHECK_GE(work_batch_size, 1);
536 controller_->SetWorkBatchSize(work_batch_size);
537 }
538
AddTaskObserver(MessageLoop::TaskObserver * task_observer)539 void SequenceManagerImpl::AddTaskObserver(
540 MessageLoop::TaskObserver* task_observer) {
541 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
542 main_thread_only().task_observers.AddObserver(task_observer);
543 }
544
RemoveTaskObserver(MessageLoop::TaskObserver * task_observer)545 void SequenceManagerImpl::RemoveTaskObserver(
546 MessageLoop::TaskObserver* task_observer) {
547 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
548 main_thread_only().task_observers.RemoveObserver(task_observer);
549 }
550
AddTaskTimeObserver(TaskTimeObserver * task_time_observer)551 void SequenceManagerImpl::AddTaskTimeObserver(
552 TaskTimeObserver* task_time_observer) {
553 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
554 main_thread_only().task_time_observers.AddObserver(task_time_observer);
555 }
556
RemoveTaskTimeObserver(TaskTimeObserver * task_time_observer)557 void SequenceManagerImpl::RemoveTaskTimeObserver(
558 TaskTimeObserver* task_time_observer) {
559 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
560 main_thread_only().task_time_observers.RemoveObserver(task_time_observer);
561 }
562
GetAndClearSystemIsQuiescentBit()563 bool SequenceManagerImpl::GetAndClearSystemIsQuiescentBit() {
564 bool task_was_run =
565 main_thread_only().task_was_run_on_quiescence_monitored_queue;
566 main_thread_only().task_was_run_on_quiescence_monitored_queue = false;
567 return !task_was_run;
568 }
569
GetNextSequenceNumber()570 internal::EnqueueOrder SequenceManagerImpl::GetNextSequenceNumber() {
571 return enqueue_order_generator_.GenerateNext();
572 }
573
574 std::unique_ptr<trace_event::ConvertableToTraceFormat>
AsValueWithSelectorResult(bool should_run,internal::WorkQueue * selected_work_queue) const575 SequenceManagerImpl::AsValueWithSelectorResult(
576 bool should_run,
577 internal::WorkQueue* selected_work_queue) const {
578 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
579 std::unique_ptr<trace_event::TracedValue> state(
580 new trace_event::TracedValue());
581 TimeTicks now = NowTicks();
582 state->BeginArray("active_queues");
583 for (auto* const queue : main_thread_only().active_queues)
584 queue->AsValueInto(now, state.get());
585 state->EndArray();
586 state->BeginArray("queues_to_gracefully_shutdown");
587 for (const auto& pair : main_thread_only().queues_to_gracefully_shutdown)
588 pair.first->AsValueInto(now, state.get());
589 state->EndArray();
590 state->BeginArray("queues_to_delete");
591 for (const auto& pair : main_thread_only().queues_to_delete)
592 pair.first->AsValueInto(now, state.get());
593 state->EndArray();
594 state->BeginDictionary("selector");
595 main_thread_only().selector.AsValueInto(state.get());
596 state->EndDictionary();
597 if (should_run) {
598 state->SetString("selected_queue",
599 selected_work_queue->task_queue()->GetName());
600 state->SetString("work_queue_name", selected_work_queue->name());
601 }
602
603 state->BeginArray("time_domains");
604 for (auto* time_domain : main_thread_only().time_domains)
605 time_domain->AsValueInto(state.get());
606 state->EndArray();
607 {
608 AutoLock lock(any_thread_lock_);
609 state->BeginArray("has_incoming_immediate_work");
610 for (const internal::IncomingImmediateWorkList* iter =
611 any_thread().incoming_immediate_work_list;
612 iter; iter = iter->next) {
613 state->AppendString(iter->queue->GetName());
614 }
615 state->EndArray();
616 }
617 return std::move(state);
618 }
619
OnTaskQueueEnabled(internal::TaskQueueImpl * queue)620 void SequenceManagerImpl::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
621 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
622 DCHECK(queue->IsQueueEnabled());
623 // Only schedule DoWork if there's something to do.
624 if (queue->HasTaskToRunImmediately() && !queue->BlockedByFence())
625 MaybeScheduleImmediateWork(FROM_HERE);
626 }
627
SweepCanceledDelayedTasks()628 void SequenceManagerImpl::SweepCanceledDelayedTasks() {
629 std::map<TimeDomain*, TimeTicks> time_domain_now;
630 for (auto* const queue : main_thread_only().active_queues)
631 SweepCanceledDelayedTasksInQueue(queue, &time_domain_now);
632 for (const auto& pair : main_thread_only().queues_to_gracefully_shutdown)
633 SweepCanceledDelayedTasksInQueue(pair.first, &time_domain_now);
634 }
635
TakeQueuesToGracefullyShutdownFromHelper()636 void SequenceManagerImpl::TakeQueuesToGracefullyShutdownFromHelper() {
637 std::vector<std::unique_ptr<internal::TaskQueueImpl>> queues =
638 graceful_shutdown_helper_->TakeQueues();
639 for (std::unique_ptr<internal::TaskQueueImpl>& queue : queues) {
640 main_thread_only().queues_to_gracefully_shutdown[queue.get()] =
641 std::move(queue);
642 }
643 }
644
CleanUpQueues()645 void SequenceManagerImpl::CleanUpQueues() {
646 TakeQueuesToGracefullyShutdownFromHelper();
647
648 for (auto it = main_thread_only().queues_to_gracefully_shutdown.begin();
649 it != main_thread_only().queues_to_gracefully_shutdown.end();) {
650 if (it->first->IsEmpty()) {
651 UnregisterTaskQueueImpl(std::move(it->second));
652 main_thread_only().active_queues.erase(it->first);
653 main_thread_only().queues_to_gracefully_shutdown.erase(it++);
654 } else {
655 ++it;
656 }
657 }
658 main_thread_only().queues_to_delete.clear();
659 }
660
661 scoped_refptr<internal::GracefulQueueShutdownHelper>
GetGracefulQueueShutdownHelper() const662 SequenceManagerImpl::GetGracefulQueueShutdownHelper() const {
663 return graceful_shutdown_helper_;
664 }
665
GetWeakPtr()666 WeakPtr<SequenceManagerImpl> SequenceManagerImpl::GetWeakPtr() {
667 return weak_factory_.GetWeakPtr();
668 }
669
SetDefaultTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner)670 void SequenceManagerImpl::SetDefaultTaskRunner(
671 scoped_refptr<SingleThreadTaskRunner> task_runner) {
672 controller_->SetDefaultTaskRunner(task_runner);
673 }
674
GetTickClock() const675 const TickClock* SequenceManagerImpl::GetTickClock() const {
676 return controller_->GetClock();
677 }
678
NowTicks() const679 TimeTicks SequenceManagerImpl::NowTicks() const {
680 return controller_->GetClock()->NowTicks();
681 }
682
ShouldRecordCPUTimeForTask()683 bool SequenceManagerImpl::ShouldRecordCPUTimeForTask() {
684 return ThreadTicks::IsSupported() &&
685 main_thread_only().uniform_distribution(
686 main_thread_only().random_generator) <
687 metric_recording_settings_
688 .task_sampling_rate_for_recording_cpu_time;
689 }
690
691 const SequenceManager::MetricRecordingSettings&
GetMetricRecordingSettings() const692 SequenceManagerImpl::GetMetricRecordingSettings() const {
693 return metric_recording_settings_;
694 }
695
MSVC_DISABLE_OPTIMIZE()696 MSVC_DISABLE_OPTIMIZE()
697 bool SequenceManagerImpl::Validate() {
698 return memory_corruption_sentinel_ == kMemoryCorruptionSentinelValue;
699 }
MSVC_ENABLE_OPTIMIZE()700 MSVC_ENABLE_OPTIMIZE()
701
702 void SequenceManagerImpl::EnableCrashKeys(
703 const char* file_name_crash_key_name,
704 const char* function_name_crash_key_name) {
705 DCHECK(!main_thread_only().file_name_crash_key);
706 DCHECK(!main_thread_only().function_name_crash_key);
707 #if !defined(OS_NACL)
708 main_thread_only().file_name_crash_key = debug::AllocateCrashKeyString(
709 file_name_crash_key_name, debug::CrashKeySize::Size64);
710 main_thread_only().function_name_crash_key = debug::AllocateCrashKeyString(
711 function_name_crash_key_name, debug::CrashKeySize::Size64);
712 #endif // OS_NACL
713 }
714
currently_executing_task_queue() const715 internal::TaskQueueImpl* SequenceManagerImpl::currently_executing_task_queue()
716 const {
717 if (main_thread_only().task_execution_stack.empty())
718 return nullptr;
719 return main_thread_only().task_execution_stack.rbegin()->task_queue;
720 }
721
722 } // namespace internal
723 } // namespace sequence_manager
724 } // namespace base
725