Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(604)

Side by Side Diff: components/scheduler/base/task_queue_impl.cc

Issue 2118903002: scheduler: Move the Blink scheduler into Blink (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Another GYP fix Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 "components/scheduler/base/task_queue_impl.h"
6
7 #include "base/trace_event/blame_context.h"
8 #include "components/scheduler/base/task_queue_manager.h"
9 #include "components/scheduler/base/task_queue_manager_delegate.h"
10 #include "components/scheduler/base/time_domain.h"
11 #include "components/scheduler/base/work_queue.h"
12
13 namespace scheduler {
14 namespace internal {
15
16 TaskQueueImpl::TaskQueueImpl(
17 TaskQueueManager* task_queue_manager,
18 TimeDomain* time_domain,
19 const Spec& spec,
20 const char* disabled_by_default_tracing_category,
21 const char* disabled_by_default_verbose_tracing_category)
22 : thread_id_(base::PlatformThread::CurrentId()),
23 any_thread_(task_queue_manager, spec.pump_policy, time_domain),
24 name_(spec.name),
25 disabled_by_default_tracing_category_(
26 disabled_by_default_tracing_category),
27 disabled_by_default_verbose_tracing_category_(
28 disabled_by_default_verbose_tracing_category),
29 main_thread_only_(task_queue_manager,
30 spec.pump_policy,
31 this,
32 time_domain),
33 wakeup_policy_(spec.wakeup_policy),
34 should_monitor_quiescence_(spec.should_monitor_quiescence),
35 should_notify_observers_(spec.should_notify_observers),
36 should_report_when_execution_blocked_(
37 spec.should_report_when_execution_blocked) {
38 DCHECK(time_domain);
39 time_domain->RegisterQueue(this);
40 }
41
42 TaskQueueImpl::~TaskQueueImpl() {
43 #if DCHECK_IS_ON()
44 base::AutoLock lock(any_thread_lock_);
45 // NOTE this check shouldn't fire because |TaskQueueManager::queues_|
46 // contains a strong reference to this TaskQueueImpl and the TaskQueueManager
47 // destructor calls UnregisterTaskQueue on all task queues.
48 DCHECK(any_thread().task_queue_manager == nullptr)
49 << "UnregisterTaskQueue must be called first!";
50
51 #endif
52 }
53
54 TaskQueueImpl::Task::Task()
55 : PendingTask(tracked_objects::Location(),
56 base::Closure(),
57 base::TimeTicks(),
58 true),
59 #ifndef NDEBUG
60 enqueue_order_set_(false),
61 #endif
62 enqueue_order_(0) {
63 sequence_num = 0;
64 }
65
66 TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
67 const base::Closure& task,
68 base::TimeTicks desired_run_time,
69 EnqueueOrder sequence_number,
70 bool nestable)
71 : PendingTask(posted_from, task, desired_run_time, nestable),
72 #ifndef NDEBUG
73 enqueue_order_set_(false),
74 #endif
75 enqueue_order_(0) {
76 sequence_num = sequence_number;
77 }
78
79 TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
80 const base::Closure& task,
81 base::TimeTicks desired_run_time,
82 EnqueueOrder sequence_number,
83 bool nestable,
84 EnqueueOrder enqueue_order)
85 : PendingTask(posted_from, task, desired_run_time, nestable),
86 #ifndef NDEBUG
87 enqueue_order_set_(true),
88 #endif
89 enqueue_order_(enqueue_order) {
90 sequence_num = sequence_number;
91 }
92
93 TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager,
94 PumpPolicy pump_policy,
95 TimeDomain* time_domain)
96 : task_queue_manager(task_queue_manager),
97 pump_policy(pump_policy),
98 time_domain(time_domain) {}
99
100 TaskQueueImpl::AnyThread::~AnyThread() {}
101
102 TaskQueueImpl::MainThreadOnly::MainThreadOnly(
103 TaskQueueManager* task_queue_manager,
104 PumpPolicy pump_policy,
105 TaskQueueImpl* task_queue,
106 TimeDomain* time_domain)
107 : task_queue_manager(task_queue_manager),
108 pump_policy(pump_policy),
109 time_domain(time_domain),
110 delayed_work_queue(new WorkQueue(task_queue, "delayed")),
111 immediate_work_queue(new WorkQueue(task_queue, "immediate")),
112 set_index(0),
113 is_enabled(true),
114 blame_context(nullptr) {}
115
116 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {}
117
118 void TaskQueueImpl::UnregisterTaskQueue() {
119 base::AutoLock lock(any_thread_lock_);
120 if (main_thread_only().time_domain)
121 main_thread_only().time_domain->UnregisterQueue(this);
122 if (!any_thread().task_queue_manager)
123 return;
124 any_thread().time_domain = nullptr;
125 main_thread_only().time_domain = nullptr;
126 any_thread().task_queue_manager->UnregisterTaskQueue(this);
127
128 any_thread().task_queue_manager = nullptr;
129 main_thread_only().task_queue_manager = nullptr;
130 main_thread_only().delayed_incoming_queue = std::priority_queue<Task>();
131 any_thread().immediate_incoming_queue = std::queue<Task>();
132 main_thread_only().immediate_work_queue.reset();
133 main_thread_only().delayed_work_queue.reset();
134 }
135
136 bool TaskQueueImpl::RunsTasksOnCurrentThread() const {
137 base::AutoLock lock(any_thread_lock_);
138 return base::PlatformThread::CurrentId() == thread_id_;
139 }
140
141 bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here,
142 const base::Closure& task,
143 base::TimeDelta delay) {
144 if (delay.is_zero())
145 return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL);
146
147 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL);
148 }
149
150 bool TaskQueueImpl::PostNonNestableDelayedTask(
151 const tracked_objects::Location& from_here,
152 const base::Closure& task,
153 base::TimeDelta delay) {
154 if (delay.is_zero())
155 return PostImmediateTaskImpl(from_here, task, TaskType::NON_NESTABLE);
156
157 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE);
158 }
159
160 bool TaskQueueImpl::PostImmediateTaskImpl(
161 const tracked_objects::Location& from_here,
162 const base::Closure& task,
163 TaskType task_type) {
164 base::AutoLock lock(any_thread_lock_);
165 if (!any_thread().task_queue_manager)
166 return false;
167
168 EnqueueOrder sequence_number =
169 any_thread().task_queue_manager->GetNextSequenceNumber();
170
171 PushOntoImmediateIncomingQueueLocked(
172 Task(from_here, task, base::TimeTicks(), sequence_number,
173 task_type != TaskType::NON_NESTABLE, sequence_number));
174 return true;
175 }
176
177 bool TaskQueueImpl::PostDelayedTaskImpl(
178 const tracked_objects::Location& from_here,
179 const base::Closure& task,
180 base::TimeDelta delay,
181 TaskType task_type) {
182 DCHECK_GT(delay, base::TimeDelta());
183 if (base::PlatformThread::CurrentId() == thread_id_) {
184 // Lock-free fast path for delayed tasks posted from the main thread.
185 if (!main_thread_only().task_queue_manager)
186 return false;
187
188 EnqueueOrder sequence_number =
189 main_thread_only().task_queue_manager->GetNextSequenceNumber();
190
191 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now();
192 base::TimeTicks time_domain_delayed_run_time =
193 main_thread_only().time_domain->ComputeDelayedRunTime(time_domain_now,
194 delay);
195 PushOntoDelayedIncomingQueueFromMainThread(
196 Task(from_here, task, time_domain_delayed_run_time, sequence_number,
197 task_type != TaskType::NON_NESTABLE),
198 time_domain_now);
199 } else {
200 // NOTE posting a delayed task from a different thread is not expected to
201 // be common. This pathway is less optimal than perhaps it could be
202 // because it causes two main thread tasks to be run. Should this
203 // assumption prove to be false in future, we may need to revisit this.
204 base::AutoLock lock(any_thread_lock_);
205 if (!any_thread().task_queue_manager)
206 return false;
207
208 EnqueueOrder sequence_number =
209 any_thread().task_queue_manager->GetNextSequenceNumber();
210
211 base::TimeTicks time_domain_now = any_thread().time_domain->Now();
212 base::TimeTicks time_domain_delayed_run_time =
213 any_thread().time_domain->ComputeDelayedRunTime(time_domain_now, delay);
214 PushOntoDelayedIncomingQueueLocked(
215 Task(from_here, task, time_domain_delayed_run_time, sequence_number,
216 task_type != TaskType::NON_NESTABLE));
217 }
218 return true;
219 }
220
221 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread(
222 Task pending_task,
223 base::TimeTicks now) {
224 main_thread_only().task_queue_manager->DidQueueTask(pending_task);
225
226 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue.
227 base::TimeTicks delayed_run_time = pending_task.delayed_run_time;
228 main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
229 main_thread_only().time_domain->ScheduleDelayedWork(
230 this, delayed_run_time, now);
231 TraceQueueSize(false);
232 }
233
234 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) {
235 any_thread().task_queue_manager->DidQueueTask(pending_task);
236
237 int thread_hop_task_sequence_number =
238 any_thread().task_queue_manager->GetNextSequenceNumber();
239 PushOntoImmediateIncomingQueueLocked(Task(
240 FROM_HERE,
241 base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this,
242 base::Passed(&pending_task)),
243 base::TimeTicks(), thread_hop_task_sequence_number, false,
244 thread_hop_task_sequence_number));
245 }
246
247 void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(Task pending_task) {
248 if (any_thread().immediate_incoming_queue.empty())
249 any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
250 if (any_thread().pump_policy == PumpPolicy::AUTO &&
251 any_thread().immediate_incoming_queue.empty()) {
252 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
253 }
254 any_thread().task_queue_manager->DidQueueTask(pending_task);
255 any_thread().immediate_incoming_queue.push(std::move(pending_task));
256 TraceQueueSize(true);
257 }
258
259 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) {
260 DCHECK(main_thread_checker_.CalledOnValidThread());
261 base::TimeTicks delayed_run_time = pending_task.delayed_run_time;
262 main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
263 main_thread_only().time_domain->ScheduleDelayedWork(
264 this, delayed_run_time,
265 main_thread_only().time_domain->Now());
266 }
267
268 void TaskQueueImpl::SetQueueEnabled(bool enabled) {
269 if (main_thread_only().is_enabled == enabled)
270 return;
271 main_thread_only().is_enabled = enabled;
272 if (!main_thread_only().task_queue_manager)
273 return;
274 if (enabled) {
275 main_thread_only().task_queue_manager->selector_.EnableQueue(this);
276 } else {
277 main_thread_only().task_queue_manager->selector_.DisableQueue(this);
278 }
279 }
280
281 bool TaskQueueImpl::IsQueueEnabled() const {
282 return main_thread_only().is_enabled;
283 }
284
285 bool TaskQueueImpl::IsEmpty() const {
286 if (!main_thread_only().delayed_work_queue->Empty() ||
287 !main_thread_only().immediate_work_queue->Empty()) {
288 return false;
289 }
290
291 base::AutoLock lock(any_thread_lock_);
292 return any_thread().immediate_incoming_queue.empty() &&
293 main_thread_only().delayed_incoming_queue.empty();
294 }
295
296 bool TaskQueueImpl::HasPendingImmediateWork() const {
297 if (!main_thread_only().delayed_work_queue->Empty() ||
298 !main_thread_only().immediate_work_queue->Empty()) {
299 return true;
300 }
301
302 return NeedsPumping();
303 }
304
305 bool TaskQueueImpl::NeedsPumping() const {
306 if (!main_thread_only().immediate_work_queue->Empty())
307 return false;
308
309 base::AutoLock lock(any_thread_lock_);
310 if (!any_thread().immediate_incoming_queue.empty())
311 return true;
312
313 // If there's no immediate Incoming work then we only need pumping if there
314 // is a delayed task that should be running now.
315 if (main_thread_only().delayed_incoming_queue.empty())
316 return false;
317
318 return main_thread_only().delayed_incoming_queue.top().delayed_run_time <=
319 main_thread_only().time_domain->CreateLazyNow().Now();
320 }
321
322 bool TaskQueueImpl::TaskIsOlderThanQueuedImmediateTasksLocked(
323 const Task* task) {
324 // A null task is passed when UpdateQueue is called before any task is run.
325 // In this case we don't want to pump an after_wakeup queue, so return true
326 // here.
327 if (!task)
328 return true;
329
330 // Return false if task is newer than the oldest immediate task.
331 if (!any_thread().immediate_incoming_queue.empty() &&
332 task->enqueue_order() >
333 any_thread().immediate_incoming_queue.front().enqueue_order()) {
334 return false;
335 }
336 return true;
337 }
338
339 bool TaskQueueImpl::TaskIsOlderThanQueuedDelayedTasks(const Task* task) {
340 DCHECK(main_thread_checker_.CalledOnValidThread());
341 // A null task is passed when UpdateQueue is called before any task is run.
342 // In this case we don't want to pump an after_wakeup queue, so return true
343 // here.
344 if (!task)
345 return true;
346
347 EnqueueOrder enqueue_order;
348 if (!main_thread_only().delayed_work_queue->GetFrontTaskEnqueueOrder(
349 &enqueue_order)) {
350 return true;
351 }
352
353 return task->enqueue_order() < enqueue_order;
354 }
355
356 bool TaskQueueImpl::ShouldAutoPumpImmediateQueueLocked(
357 bool should_trigger_wakeup,
358 const Task* previous_task) {
359 if (main_thread_only().pump_policy == PumpPolicy::MANUAL)
360 return false;
361 if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP &&
362 (!should_trigger_wakeup ||
363 TaskIsOlderThanQueuedImmediateTasksLocked(previous_task)))
364 return false;
365 return true;
366 }
367
368 bool TaskQueueImpl::ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup,
369 const Task* previous_task) {
370 if (main_thread_only().pump_policy == PumpPolicy::MANUAL)
371 return false;
372 if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP &&
373 (!should_trigger_wakeup ||
374 TaskIsOlderThanQueuedDelayedTasks(previous_task)))
375 return false;
376 return true;
377 }
378
379 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) {
380 // Enqueue all delayed tasks that should be running now.
381 while (!main_thread_only().delayed_incoming_queue.empty() &&
382 main_thread_only().delayed_incoming_queue.top().delayed_run_time <=
383 lazy_now->Now()) {
384 // Note: the const_cast is needed because there is no direct way to move
385 // elements out of a priority queue. The queue must not be modified between
386 // the top() and the pop().
387 main_thread_only().delayed_work_queue->PushAndSetEnqueueOrder(
388 std::move(
389 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top())),
390 main_thread_only().task_queue_manager->GetNextSequenceNumber());
391 main_thread_only().delayed_incoming_queue.pop();
392 }
393 }
394
395 void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now,
396 bool should_trigger_wakeup,
397 const Task* previous_task) {
398 if (!main_thread_only().task_queue_manager)
399 return;
400 if (!ShouldAutoPumpDelayedQueue(should_trigger_wakeup, previous_task))
401 return;
402 MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now);
403 TraceQueueSize(false);
404 }
405
406 void TaskQueueImpl::UpdateImmediateWorkQueue(bool should_trigger_wakeup,
407 const Task* previous_task) {
408 DCHECK(main_thread_only().immediate_work_queue->Empty());
409 base::AutoLock lock(any_thread_lock_);
410 if (!main_thread_only().task_queue_manager)
411 return;
412 if (!ShouldAutoPumpImmediateQueueLocked(should_trigger_wakeup, previous_task))
413 return;
414
415 main_thread_only().immediate_work_queue->SwapLocked(
416 any_thread().immediate_incoming_queue);
417
418 // |any_thread().immediate_incoming_queue| is now empty so
419 // TimeDomain::UpdateQueues no longer needs to consider this queue for
420 // reloading.
421 main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this);
422 }
423
424 void TaskQueueImpl::TraceQueueSize(bool is_locked) const {
425 bool is_tracing;
426 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_,
427 &is_tracing);
428 if (!is_tracing)
429 return;
430
431 // It's only safe to access the work queues from the main thread.
432 // TODO(alexclarke): We should find another way of tracing this
433 if (base::PlatformThread::CurrentId() != thread_id_)
434 return;
435
436 if (!is_locked)
437 any_thread_lock_.Acquire();
438 else
439 any_thread_lock_.AssertAcquired();
440 TRACE_COUNTER1(disabled_by_default_tracing_category_, GetName(),
441 any_thread().immediate_incoming_queue.size() +
442 main_thread_only().immediate_work_queue->Size() +
443 main_thread_only().delayed_work_queue->Size() +
444 main_thread_only().delayed_incoming_queue.size());
445 if (!is_locked)
446 any_thread_lock_.Release();
447 }
448
449 void TaskQueueImpl::SetPumpPolicy(PumpPolicy pump_policy) {
450 base::AutoLock lock(any_thread_lock_);
451 if (pump_policy == PumpPolicy::AUTO &&
452 any_thread().pump_policy != PumpPolicy::AUTO) {
453 PumpQueueLocked(true);
454 }
455 any_thread().pump_policy = pump_policy;
456 main_thread_only().pump_policy = pump_policy;
457 }
458
459 TaskQueue::PumpPolicy TaskQueueImpl::GetPumpPolicy() const {
460 return main_thread_only().pump_policy;
461 }
462
463 void TaskQueueImpl::PumpQueueLocked(bool may_post_dowork) {
464 TRACE_EVENT1(disabled_by_default_tracing_category_,
465 "TaskQueueImpl::PumpQueueLocked", "queue", name_);
466 TaskQueueManager* task_queue_manager = any_thread().task_queue_manager;
467 if (!task_queue_manager)
468 return;
469
470 LazyNow lazy_now(main_thread_only().time_domain->CreateLazyNow());
471 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now);
472
473 while (!any_thread().immediate_incoming_queue.empty()) {
474 main_thread_only().immediate_work_queue->Push(
475 std::move(any_thread().immediate_incoming_queue.front()));
476 any_thread().immediate_incoming_queue.pop();
477 }
478
479 // |immediate_incoming_queue| is now empty so TimeDomain::UpdateQueues no
480 // longer needs to consider this queue for reloading.
481 main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this);
482
483 if (main_thread_only().immediate_work_queue->Empty() &&
484 main_thread_only().delayed_work_queue->Empty()) {
485 return;
486 }
487
488 if (may_post_dowork)
489 task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
490 }
491
492 void TaskQueueImpl::PumpQueue(bool may_post_dowork) {
493 base::AutoLock lock(any_thread_lock_);
494 PumpQueueLocked(may_post_dowork);
495 }
496
497 const char* TaskQueueImpl::GetName() const {
498 return name_;
499 }
500
501 void TaskQueueImpl::SetQueuePriority(QueuePriority priority) {
502 if (!main_thread_only().task_queue_manager || priority == GetQueuePriority())
503 return;
504 main_thread_only().task_queue_manager->selector_.SetQueuePriority(this,
505 priority);
506 }
507
508 TaskQueueImpl::QueuePriority TaskQueueImpl::GetQueuePriority() const {
509 size_t set_index = immediate_work_queue()->work_queue_set_index();
510 DCHECK_EQ(set_index, delayed_work_queue()->work_queue_set_index());
511 return static_cast<TaskQueue::QueuePriority>(set_index);
512 }
513
514 // static
515 const char* TaskQueueImpl::PumpPolicyToString(
516 TaskQueue::PumpPolicy pump_policy) {
517 switch (pump_policy) {
518 case TaskQueue::PumpPolicy::AUTO:
519 return "auto";
520 case TaskQueue::PumpPolicy::AFTER_WAKEUP:
521 return "after_wakeup";
522 case TaskQueue::PumpPolicy::MANUAL:
523 return "manual";
524 default:
525 NOTREACHED();
526 return nullptr;
527 }
528 }
529
530 // static
531 const char* TaskQueueImpl::WakeupPolicyToString(
532 TaskQueue::WakeupPolicy wakeup_policy) {
533 switch (wakeup_policy) {
534 case TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES:
535 return "can_wake_other_queues";
536 case TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES:
537 return "dont_wake_other_queues";
538 default:
539 NOTREACHED();
540 return nullptr;
541 }
542 }
543
544 // static
545 const char* TaskQueueImpl::PriorityToString(QueuePriority priority) {
546 switch (priority) {
547 case CONTROL_PRIORITY:
548 return "control";
549 case HIGH_PRIORITY:
550 return "high";
551 case NORMAL_PRIORITY:
552 return "normal";
553 case BEST_EFFORT_PRIORITY:
554 return "best_effort";
555 default:
556 NOTREACHED();
557 return nullptr;
558 }
559 }
560
561 void TaskQueueImpl::AsValueInto(base::trace_event::TracedValue* state) const {
562 base::AutoLock lock(any_thread_lock_);
563 state->BeginDictionary();
564 state->SetString("name", GetName());
565 state->SetBoolean("enabled", main_thread_only().is_enabled);
566 state->SetString("time_domain_name",
567 main_thread_only().time_domain->GetName());
568 state->SetString("pump_policy", PumpPolicyToString(any_thread().pump_policy));
569 state->SetString("wakeup_policy", WakeupPolicyToString(wakeup_policy_));
570 bool verbose_tracing_enabled = false;
571 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
572 disabled_by_default_verbose_tracing_category_, &verbose_tracing_enabled);
573 state->SetInteger("immediate_incoming_queue_size",
574 any_thread().immediate_incoming_queue.size());
575 state->SetInteger("delayed_incoming_queue_size",
576 main_thread_only().delayed_incoming_queue.size());
577 state->SetInteger("immediate_work_queue_size",
578 main_thread_only().immediate_work_queue->Size());
579 state->SetInteger("delayed_work_queue_size",
580 main_thread_only().delayed_work_queue->Size());
581 if (!main_thread_only().delayed_incoming_queue.empty()) {
582 base::TimeDelta delay_to_next_task =
583 (main_thread_only().delayed_incoming_queue.top().delayed_run_time -
584 main_thread_only().time_domain->CreateLazyNow().Now());
585 state->SetDouble("delay_to_next_task_ms",
586 delay_to_next_task.InMillisecondsF());
587 }
588 if (verbose_tracing_enabled) {
589 state->BeginArray("immediate_incoming_queue");
590 QueueAsValueInto(any_thread().immediate_incoming_queue, state);
591 state->EndArray();
592 state->BeginArray("delayed_work_queue");
593 main_thread_only().delayed_work_queue->AsValueInto(state);
594 state->EndArray();
595 state->BeginArray("immediate_work_queue");
596 main_thread_only().immediate_work_queue->AsValueInto(state);
597 state->EndArray();
598 state->BeginArray("delayed_incoming_queue");
599 QueueAsValueInto(main_thread_only().delayed_incoming_queue, state);
600 state->EndArray();
601 }
602 state->SetString("priority", PriorityToString(GetQueuePriority()));
603 state->EndDictionary();
604 }
605
606 void TaskQueueImpl::AddTaskObserver(
607 base::MessageLoop::TaskObserver* task_observer) {
608 main_thread_only().task_observers.AddObserver(task_observer);
609 }
610
611 void TaskQueueImpl::RemoveTaskObserver(
612 base::MessageLoop::TaskObserver* task_observer) {
613 main_thread_only().task_observers.RemoveObserver(task_observer);
614 }
615
616 void TaskQueueImpl::NotifyWillProcessTask(
617 const base::PendingTask& pending_task) {
618 DCHECK(should_notify_observers_);
619 if (main_thread_only().blame_context)
620 main_thread_only().blame_context->Enter();
621 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver,
622 main_thread_only().task_observers,
623 WillProcessTask(pending_task));
624 }
625
626 void TaskQueueImpl::NotifyDidProcessTask(
627 const base::PendingTask& pending_task) {
628 DCHECK(should_notify_observers_);
629 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver,
630 main_thread_only().task_observers,
631 DidProcessTask(pending_task));
632 if (main_thread_only().blame_context)
633 main_thread_only().blame_context->Leave();
634 }
635
636 void TaskQueueImpl::SetTimeDomain(TimeDomain* time_domain) {
637 base::AutoLock lock(any_thread_lock_);
638 DCHECK(time_domain);
639 // NOTE this is similar to checking |any_thread().task_queue_manager| but the
640 // TaskQueueSelectorTests constructs TaskQueueImpl directly with a null
641 // task_queue_manager. Instead we check |any_thread().time_domain| which is
642 // another way of asserting that UnregisterTaskQueue has not been called.
643 DCHECK(any_thread().time_domain);
644 if (!any_thread().time_domain)
645 return;
646 DCHECK(main_thread_checker_.CalledOnValidThread());
647 if (time_domain == main_thread_only().time_domain)
648 return;
649
650 main_thread_only().time_domain->MigrateQueue(this, time_domain);
651 main_thread_only().time_domain = time_domain;
652 any_thread().time_domain = time_domain;
653 }
654
655 TimeDomain* TaskQueueImpl::GetTimeDomain() const {
656 if (base::PlatformThread::CurrentId() == thread_id_)
657 return main_thread_only().time_domain;
658
659 base::AutoLock lock(any_thread_lock_);
660 return any_thread().time_domain;
661 }
662
663 void TaskQueueImpl::SetBlameContext(
664 base::trace_event::BlameContext* blame_context) {
665 main_thread_only().blame_context = blame_context;
666 }
667
668 // static
669 void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue,
670 base::trace_event::TracedValue* state) {
671 // Remove const to search |queue| in the destructive manner. Restore the
672 // content from |visited| later.
673 std::queue<Task>* mutable_queue = const_cast<std::queue<Task>*>(&queue);
674 std::queue<Task> visited;
675 while (!mutable_queue->empty()) {
676 TaskAsValueInto(mutable_queue->front(), state);
677 visited.push(std::move(mutable_queue->front()));
678 mutable_queue->pop();
679 }
680 *mutable_queue = std::move(visited);
681 }
682
683 // static
684 void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue,
685 base::trace_event::TracedValue* state) {
686 // Remove const to search |queue| in the destructive manner. Restore the
687 // content from |visited| later.
688 std::priority_queue<Task>* mutable_queue =
689 const_cast<std::priority_queue<Task>*>(&queue);
690 std::priority_queue<Task> visited;
691 while (!mutable_queue->empty()) {
692 TaskAsValueInto(mutable_queue->top(), state);
693 visited.push(std::move(const_cast<Task&>(mutable_queue->top())));
694 mutable_queue->pop();
695 }
696 *mutable_queue = std::move(visited);
697 }
698
699 // static
700 void TaskQueueImpl::TaskAsValueInto(const Task& task,
701 base::trace_event::TracedValue* state) {
702 state->BeginDictionary();
703 state->SetString("posted_from", task.posted_from.ToString());
704 #ifndef NDEBUG
705 if (task.enqueue_order_set())
706 state->SetInteger("enqueue_order", task.enqueue_order());
707 #else
708 state->SetInteger("enqueue_order", task.enqueue_order());
709 #endif
710 state->SetInteger("sequence_num", task.sequence_num);
711 state->SetBoolean("nestable", task.nestable);
712 state->SetBoolean("is_high_res", task.is_high_res);
713 state->SetDouble(
714 "delayed_run_time",
715 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L);
716 state->EndDictionary();
717 }
718
719 } // namespace internal
720 } // namespace scheduler
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698