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