OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/scheduler/base/task_queue_impl.h" | 5 #include "platform/scheduler/base/task_queue_impl.h" |
6 | 6 |
7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "base/trace_event/blame_context.h" | 10 #include "base/trace_event/blame_context.h" |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 : task_queue_manager(task_queue_manager), time_domain(time_domain) {} | 147 : task_queue_manager(task_queue_manager), time_domain(time_domain) {} |
148 | 148 |
149 TaskQueueImpl::AnyThread::~AnyThread() {} | 149 TaskQueueImpl::AnyThread::~AnyThread() {} |
150 | 150 |
151 TaskQueueImpl::MainThreadOnly::MainThreadOnly( | 151 TaskQueueImpl::MainThreadOnly::MainThreadOnly( |
152 TaskQueueManager* task_queue_manager, | 152 TaskQueueManager* task_queue_manager, |
153 TaskQueueImpl* task_queue, | 153 TaskQueueImpl* task_queue, |
154 TimeDomain* time_domain) | 154 TimeDomain* time_domain) |
155 : task_queue_manager(task_queue_manager), | 155 : task_queue_manager(task_queue_manager), |
156 time_domain(time_domain), | 156 time_domain(time_domain), |
157 delayed_work_queue(new WorkQueue(task_queue, "delayed")), | 157 delayed_work_queue( |
158 immediate_work_queue(new WorkQueue(task_queue, "immediate")), | 158 new WorkQueue(task_queue, "delayed", WorkQueue::QueueType::DELAYED)), |
| 159 immediate_work_queue(new WorkQueue(task_queue, |
| 160 "immediate", |
| 161 WorkQueue::QueueType::IMMEDIATE)), |
159 set_index(0), | 162 set_index(0), |
160 is_enabled_refcount(0), | 163 is_enabled_refcount(0), |
161 voter_refcount(0), | 164 voter_refcount(0), |
162 blame_context(nullptr), | 165 blame_context(nullptr), |
163 current_fence(0) {} | 166 current_fence(0) {} |
164 | 167 |
165 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} | 168 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} |
166 | 169 |
167 void TaskQueueImpl::UnregisterTaskQueue() { | 170 void TaskQueueImpl::UnregisterTaskQueue() { |
168 base::AutoLock lock(any_thread_lock_); | 171 base::AutoLock lock(any_thread_lock_); |
169 if (main_thread_only().time_domain) | 172 if (main_thread_only().time_domain) |
170 main_thread_only().time_domain->UnregisterQueue(this); | 173 main_thread_only().time_domain->UnregisterQueue(this); |
171 if (!any_thread().task_queue_manager) | 174 if (!any_thread().task_queue_manager) |
172 return; | 175 return; |
173 any_thread().time_domain = nullptr; | 176 any_thread().time_domain = nullptr; |
174 main_thread_only().time_domain = nullptr; | 177 main_thread_only().time_domain = nullptr; |
175 any_thread().task_queue_manager->UnregisterTaskQueue(this); | 178 any_thread().task_queue_manager->UnregisterTaskQueue(this); |
176 | 179 |
177 any_thread().task_queue_manager = nullptr; | 180 any_thread().task_queue_manager = nullptr; |
178 main_thread_only().task_queue_manager = nullptr; | 181 main_thread_only().task_queue_manager = nullptr; |
179 main_thread_only().delayed_incoming_queue = std::priority_queue<Task>(); | 182 main_thread_only().delayed_incoming_queue = std::priority_queue<Task>(); |
180 any_thread().immediate_incoming_queue = std::queue<Task>(); | 183 any_thread().immediate_incoming_queue = std::queue<Task>(); |
181 main_thread_only().immediate_work_queue.reset(); | 184 main_thread_only().immediate_work_queue.reset(); |
182 main_thread_only().delayed_work_queue.reset(); | 185 main_thread_only().delayed_work_queue.reset(); |
183 } | 186 } |
184 | 187 |
185 bool TaskQueueImpl::RunsTasksOnCurrentThread() const { | 188 bool TaskQueueImpl::RunsTasksOnCurrentThread() const { |
186 base::AutoLock lock(any_thread_lock_); | |
187 return base::PlatformThread::CurrentId() == thread_id_; | 189 return base::PlatformThread::CurrentId() == thread_id_; |
188 } | 190 } |
189 | 191 |
190 bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, | 192 bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, |
191 const base::Closure& task, | 193 const base::Closure& task, |
192 base::TimeDelta delay) { | 194 base::TimeDelta delay) { |
193 if (delay.is_zero()) | 195 if (delay.is_zero()) |
194 return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); | 196 return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); |
195 | 197 |
196 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); | 198 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 } | 320 } |
319 TraceQueueSize(false); | 321 TraceQueueSize(false); |
320 } | 322 } |
321 | 323 |
322 void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked( | 324 void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked( |
323 const tracked_objects::Location& posted_from, | 325 const tracked_objects::Location& posted_from, |
324 const base::Closure& task, | 326 const base::Closure& task, |
325 base::TimeTicks desired_run_time, | 327 base::TimeTicks desired_run_time, |
326 EnqueueOrder sequence_number, | 328 EnqueueOrder sequence_number, |
327 bool nestable) { | 329 bool nestable) { |
328 if (any_thread().immediate_incoming_queue.empty()) | |
329 any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); | |
330 // If the |immediate_incoming_queue| is empty we need a DoWork posted to make | 330 // If the |immediate_incoming_queue| is empty we need a DoWork posted to make |
331 // it run. | 331 // it run. |
332 if (any_thread().immediate_incoming_queue.empty()) { | 332 if (any_thread().immediate_incoming_queue.empty()) { |
333 // There's no point posting a DoWork for a disabled queue, however we can | 333 // There's no point posting a DoWork for a blocked or disabled queue, |
334 // only tell if it's disabled from the main thread. | 334 // although we can only determine that on the main thread. |
335 if (base::PlatformThread::CurrentId() == thread_id_) { | 335 bool ensure_do_work_posted = !RunsTasksOnCurrentThread() || |
336 if (IsQueueEnabled() && !BlockedByFenceLocked()) | 336 (IsQueueEnabled() && !BlockedByFenceLocked()); |
337 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 337 any_thread().task_queue_manager->OnQueueHasImmediateWork( |
338 } else { | 338 this, ensure_do_work_posted); |
339 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 339 any_thread().time_domain->OnQueueHasImmediateWork(this); |
340 } | |
341 } | 340 } |
| 341 |
342 any_thread().immediate_incoming_queue.emplace( | 342 any_thread().immediate_incoming_queue.emplace( |
343 posted_from, task, desired_run_time, sequence_number, nestable, sequence_n
umber); | 343 posted_from, task, desired_run_time, sequence_number, nestable, |
344 any_thread().task_queue_manager->DidQueueTask( any_thread().immediate_incoming
_queue.back()); | 344 sequence_number); |
| 345 any_thread().task_queue_manager->DidQueueTask( |
| 346 any_thread().immediate_incoming_queue.back()); |
345 TraceQueueSize(true); | 347 TraceQueueSize(true); |
346 } | 348 } |
347 | 349 |
| 350 void TaskQueueImpl::ReloadImmediateWorkQueueIfEmpty() { |
| 351 if (!main_thread_only().immediate_work_queue->Empty()) |
| 352 return; |
| 353 |
| 354 base::AutoLock lock(any_thread_lock_); |
| 355 if (any_thread().immediate_incoming_queue.empty()) |
| 356 return; |
| 357 |
| 358 main_thread_only().immediate_work_queue->SwapLocked( |
| 359 any_thread().immediate_incoming_queue); |
| 360 } |
| 361 |
| 362 void TaskQueueImpl::OnImmediateWorkQueueHasBecomeEmpty( |
| 363 std::queue<TaskQueueImpl::Task>* work_queue) { |
| 364 base::AutoLock lock(any_thread_lock_); |
| 365 DCHECK(work_queue->empty()); |
| 366 |
| 367 if (any_thread().immediate_incoming_queue.empty()) |
| 368 return; |
| 369 |
| 370 std::swap(any_thread().immediate_incoming_queue, *work_queue); |
| 371 } |
| 372 |
348 bool TaskQueueImpl::IsEmpty() const { | 373 bool TaskQueueImpl::IsEmpty() const { |
349 if (!main_thread_only().delayed_work_queue->Empty() || | 374 if (!main_thread_only().delayed_work_queue->Empty() || |
350 !main_thread_only().delayed_incoming_queue.empty() || | 375 !main_thread_only().delayed_incoming_queue.empty() || |
351 !main_thread_only().immediate_work_queue->Empty()) { | 376 !main_thread_only().immediate_work_queue->Empty()) { |
352 return false; | 377 return false; |
353 } | 378 } |
354 | 379 |
355 base::AutoLock lock(any_thread_lock_); | 380 base::AutoLock lock(any_thread_lock_); |
356 return any_thread().immediate_incoming_queue.empty(); | 381 return any_thread().immediate_incoming_queue.empty(); |
357 } | 382 } |
(...skipping 29 matching lines...) Expand all Loading... |
387 return !any_thread().immediate_incoming_queue.empty(); | 412 return !any_thread().immediate_incoming_queue.empty(); |
388 } | 413 } |
389 | 414 |
390 base::Optional<base::TimeTicks> TaskQueueImpl::GetNextScheduledWakeUp() { | 415 base::Optional<base::TimeTicks> TaskQueueImpl::GetNextScheduledWakeUp() { |
391 if (main_thread_only().delayed_incoming_queue.empty()) | 416 if (main_thread_only().delayed_incoming_queue.empty()) |
392 return base::nullopt; | 417 return base::nullopt; |
393 | 418 |
394 return main_thread_only().delayed_incoming_queue.top().delayed_run_time; | 419 return main_thread_only().delayed_incoming_queue.top().delayed_run_time; |
395 } | 420 } |
396 | 421 |
397 void TaskQueueImpl::WakeUpForDelayedWork(LazyNow* lazy_now) { | 422 base::Optional<base::TimeTicks> TaskQueueImpl::WakeUpForDelayedWork( |
| 423 LazyNow* lazy_now) { |
398 // Enqueue all delayed tasks that should be running now, skipping any that | 424 // Enqueue all delayed tasks that should be running now, skipping any that |
399 // have been canceled. | 425 // have been canceled. |
400 while (!main_thread_only().delayed_incoming_queue.empty()) { | 426 while (!main_thread_only().delayed_incoming_queue.empty()) { |
401 Task& task = | 427 Task& task = |
402 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()); | 428 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()); |
403 if (task.task.IsCancelled()) { | 429 if (task.task.IsCancelled()) { |
404 main_thread_only().delayed_incoming_queue.pop(); | 430 main_thread_only().delayed_incoming_queue.pop(); |
405 continue; | 431 continue; |
406 } | 432 } |
407 if (task.delayed_run_time > lazy_now->Now()) | 433 if (task.delayed_run_time > lazy_now->Now()) |
408 break; | 434 break; |
409 task.set_enqueue_order( | 435 task.set_enqueue_order( |
410 main_thread_only().task_queue_manager->GetNextSequenceNumber()); | 436 main_thread_only().task_queue_manager->GetNextSequenceNumber()); |
411 main_thread_only().delayed_work_queue->Push(std::move(task)); | 437 main_thread_only().delayed_work_queue->Push(std::move(task)); |
412 main_thread_only().delayed_incoming_queue.pop(); | 438 main_thread_only().delayed_incoming_queue.pop(); |
413 } | 439 } |
414 | 440 |
415 // Make sure the next wake up is scheduled. | 441 // Make sure the next wake up is scheduled. |
416 if (!main_thread_only().delayed_incoming_queue.empty()) { | 442 if (!main_thread_only().delayed_incoming_queue.empty()) |
417 main_thread_only().time_domain->ScheduleDelayedWork( | 443 return main_thread_only().delayed_incoming_queue.top().delayed_run_time; |
418 this, main_thread_only().delayed_incoming_queue.top().delayed_run_time, | |
419 lazy_now->Now()); | |
420 } | |
421 } | |
422 | 444 |
423 bool TaskQueueImpl::MaybeUpdateImmediateWorkQueues() { | 445 return base::Optional<base::TimeTicks>(); |
424 if (!main_thread_only().task_queue_manager) | |
425 return false; | |
426 | |
427 if (!main_thread_only().immediate_work_queue->Empty()) | |
428 return true; | |
429 | |
430 base::AutoLock lock(any_thread_lock_); | |
431 main_thread_only().immediate_work_queue->SwapLocked( | |
432 any_thread().immediate_incoming_queue); | |
433 // |immediate_work_queue| is now empty so updates are no longer required. | |
434 return false; | |
435 } | 446 } |
436 | 447 |
437 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { | 448 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { |
438 bool is_tracing; | 449 bool is_tracing; |
439 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, | 450 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, |
440 &is_tracing); | 451 &is_tracing); |
441 if (!is_tracing) | 452 if (!is_tracing) |
442 return; | 453 return; |
443 | 454 |
444 // It's only safe to access the work queues from the main thread. | 455 // It's only safe to access the work queues from the main thread. |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 // another way of asserting that UnregisterTaskQueue has not been called. | 578 // another way of asserting that UnregisterTaskQueue has not been called. |
568 DCHECK(any_thread().time_domain); | 579 DCHECK(any_thread().time_domain); |
569 if (!any_thread().time_domain) | 580 if (!any_thread().time_domain) |
570 return; | 581 return; |
571 DCHECK(main_thread_checker_.CalledOnValidThread()); | 582 DCHECK(main_thread_checker_.CalledOnValidThread()); |
572 if (time_domain == main_thread_only().time_domain) | 583 if (time_domain == main_thread_only().time_domain) |
573 return; | 584 return; |
574 | 585 |
575 any_thread().time_domain = time_domain; | 586 any_thread().time_domain = time_domain; |
576 } | 587 } |
577 // We rely here on TimeDomain::MigrateQueue being thread-safe to use with | 588 |
578 // TimeDomain::Register/UnregisterAsUpdatableTaskQueue. | |
579 main_thread_only().time_domain->MigrateQueue(this, time_domain); | 589 main_thread_only().time_domain->MigrateQueue(this, time_domain); |
580 main_thread_only().time_domain = time_domain; | 590 main_thread_only().time_domain = time_domain; |
581 } | 591 } |
582 | 592 |
583 TimeDomain* TaskQueueImpl::GetTimeDomain() const { | 593 TimeDomain* TaskQueueImpl::GetTimeDomain() const { |
584 if (base::PlatformThread::CurrentId() == thread_id_) | 594 if (base::PlatformThread::CurrentId() == thread_id_) |
585 return main_thread_only().time_domain; | 595 return main_thread_only().time_domain; |
586 | 596 |
587 base::AutoLock lock(any_thread_lock_); | 597 base::AutoLock lock(any_thread_lock_); |
588 return any_thread().time_domain; | 598 return any_thread().time_domain; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 | 674 |
665 base::AutoLock lock(any_thread_lock_); | 675 base::AutoLock lock(any_thread_lock_); |
666 if (any_thread().immediate_incoming_queue.empty()) | 676 if (any_thread().immediate_incoming_queue.empty()) |
667 return true; | 677 return true; |
668 | 678 |
669 return any_thread().immediate_incoming_queue.front().enqueue_order() > | 679 return any_thread().immediate_incoming_queue.front().enqueue_order() > |
670 main_thread_only().current_fence; | 680 main_thread_only().current_fence; |
671 } | 681 } |
672 | 682 |
673 bool TaskQueueImpl::BlockedByFenceLocked() const { | 683 bool TaskQueueImpl::BlockedByFenceLocked() const { |
| 684 any_thread_lock_.AssertAcquired(); |
| 685 |
674 if (!main_thread_only().current_fence) | 686 if (!main_thread_only().current_fence) |
675 return false; | 687 return false; |
676 | 688 |
677 if (!main_thread_only().immediate_work_queue->BlockedByFence() || | 689 if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
678 !main_thread_only().delayed_work_queue->BlockedByFence()) { | 690 !main_thread_only().delayed_work_queue->BlockedByFence()) { |
679 return false; | 691 return false; |
680 } | 692 } |
681 | 693 |
682 if (any_thread().immediate_incoming_queue.empty()) | 694 if (any_thread().immediate_incoming_queue.empty()) |
683 return true; | 695 return true; |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
815 std::unique_ptr<TaskQueueImpl::QueueEnabledVoter> | 827 std::unique_ptr<TaskQueueImpl::QueueEnabledVoter> |
816 TaskQueueImpl::CreateQueueEnabledVoter() { | 828 TaskQueueImpl::CreateQueueEnabledVoter() { |
817 main_thread_only().voter_refcount++; | 829 main_thread_only().voter_refcount++; |
818 main_thread_only().is_enabled_refcount++; | 830 main_thread_only().is_enabled_refcount++; |
819 return base::MakeUnique<QueueEnabledVoterImpl>(this); | 831 return base::MakeUnique<QueueEnabledVoterImpl>(this); |
820 } | 832 } |
821 | 833 |
822 } // namespace internal | 834 } // namespace internal |
823 } // namespace scheduler | 835 } // namespace scheduler |
824 } // namespace blink | 836 } // namespace blink |
OLD | NEW |