Index: third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc |
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc |
index a68a4af5b4889e90167140c59ff298f5f6e7d8c2..1b0980a4f4e00ccf236f4bc2250683d0b744c3b7 100644 |
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc |
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc |
@@ -50,17 +50,13 @@ TaskQueueImpl::TaskQueueImpl( |
const char* disabled_by_default_tracing_category, |
const char* disabled_by_default_verbose_tracing_category) |
: thread_id_(base::PlatformThread::CurrentId()), |
- any_thread_(task_queue_manager, spec.pump_policy, time_domain), |
+ any_thread_(task_queue_manager, time_domain), |
name_(spec.name), |
disabled_by_default_tracing_category_( |
disabled_by_default_tracing_category), |
disabled_by_default_verbose_tracing_category_( |
disabled_by_default_verbose_tracing_category), |
- main_thread_only_(task_queue_manager, |
- spec.pump_policy, |
- this, |
- time_domain), |
- wakeup_policy_(spec.wakeup_policy), |
+ main_thread_only_(task_queue_manager, this, time_domain), |
should_monitor_quiescence_(spec.should_monitor_quiescence), |
should_notify_observers_(spec.should_notify_observers), |
should_report_when_execution_blocked_( |
@@ -171,10 +167,8 @@ bool TaskQueueImpl::Task::DelayedRunTimeComparatorFn(const Task& a, |
} |
TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager, |
- PumpPolicy pump_policy, |
TimeDomain* time_domain) |
: task_queue_manager(task_queue_manager), |
- pump_policy(pump_policy), |
time_domain(time_domain), |
immediate_incoming_queue(&TaskQueueImpl::Task::EnqueueOrderComparatorFn) { |
} |
@@ -183,11 +177,9 @@ TaskQueueImpl::AnyThread::~AnyThread() {} |
TaskQueueImpl::MainThreadOnly::MainThreadOnly( |
TaskQueueManager* task_queue_manager, |
- PumpPolicy pump_policy, |
TaskQueueImpl* task_queue, |
TimeDomain* time_domain) |
: task_queue_manager(task_queue_manager), |
- pump_policy(pump_policy), |
time_domain(time_domain), |
delayed_work_queue( |
new WorkQueue(task_queue, |
@@ -199,7 +191,8 @@ TaskQueueImpl::MainThreadOnly::MainThreadOnly( |
&TaskQueueImpl::Task::EnqueueOrderComparatorFn)), |
set_index(0), |
is_enabled(true), |
- blame_context(nullptr) {} |
+ blame_context(nullptr), |
+ current_fence(0) {} |
TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} |
@@ -449,9 +442,17 @@ void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { |
void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(Task pending_task) { |
if (any_thread().immediate_incoming_queue.empty()) |
any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); |
- if (any_thread().pump_policy == PumpPolicy::AUTO && |
- any_thread().immediate_incoming_queue.empty()) { |
- any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
+ // If the |immediate_incoming_queue| is empty we need a DoWork posted to make |
+ // it run. |
+ if (any_thread().immediate_incoming_queue.empty()) { |
+ // There's no point posting a DoWork for a disabled queue, however we can |
+ // only tell if it's disabled from the main thread. |
+ if (base::PlatformThread::CurrentId() == thread_id_) { |
+ if (main_thread_only().is_enabled && !BlockedByFenceLocked()) |
+ any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
+ } else { |
+ any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
+ } |
} |
any_thread().task_queue_manager->DidQueueTask(pending_task); |
// We expect |pending_task| to be inserted at the end. Amoritized O(1). |
@@ -489,6 +490,8 @@ void TaskQueueImpl::SetQueueEnabled(bool enabled) { |
if (!main_thread_only().task_queue_manager) |
return; |
if (enabled) { |
+ // Note it's the job of the selector to tell the TaskQueueManager if |
+ // a DoWork needs posting. |
main_thread_only().task_queue_manager->selector_.EnableQueue(this); |
} else { |
main_thread_only().task_queue_manager->selector_.DisableQueue(this); |
@@ -511,86 +514,23 @@ bool TaskQueueImpl::IsEmpty() const { |
} |
bool TaskQueueImpl::HasPendingImmediateWork() const { |
+ // Any work queue tasks count as immediate work. |
if (!main_thread_only().delayed_work_queue->Empty() || |
!main_thread_only().immediate_work_queue->Empty()) { |
return true; |
} |
- return NeedsPumping(); |
-} |
- |
-bool TaskQueueImpl::NeedsPumping() const { |
- if (!main_thread_only().immediate_work_queue->Empty()) |
- return false; |
- |
- base::AutoLock lock(any_thread_lock_); |
- if (!any_thread().immediate_incoming_queue.empty()) |
- return true; |
- |
- // If there's no immediate Incoming work then we only need pumping if there |
- // is a delayed task that should be running now. |
- if (main_thread_only().delayed_incoming_queue.empty()) |
- return false; |
- |
- return main_thread_only().delayed_incoming_queue.begin()->delayed_run_time <= |
- main_thread_only().time_domain->CreateLazyNow().Now(); |
-} |
- |
-bool TaskQueueImpl::TaskIsOlderThanQueuedImmediateTasksLocked( |
- const Task* task) { |
- // A null task is passed when UpdateQueue is called before any task is run. |
- // In this case we don't want to pump an after_wakeup queue, so return true |
- // here. |
- if (!task) |
- return true; |
- |
- // Return false if task is newer than the oldest immediate task. |
- if (!any_thread().immediate_incoming_queue.empty() && |
- task->enqueue_order() > |
- any_thread().immediate_incoming_queue.begin()->enqueue_order()) { |
- return false; |
- } |
- return true; |
-} |
- |
-bool TaskQueueImpl::TaskIsOlderThanQueuedDelayedTasks(const Task* task) { |
- DCHECK(main_thread_checker_.CalledOnValidThread()); |
- // A null task is passed when UpdateQueue is called before any task is run. |
- // In this case we don't want to pump an after_wakeup queue, so return true |
- // here. |
- if (!task) |
- return true; |
- |
- EnqueueOrder enqueue_order; |
- if (!main_thread_only().delayed_work_queue->GetFrontTaskEnqueueOrder( |
- &enqueue_order)) { |
+ // Tasks on |delayed_incoming_queue| that could run now, count as |
+ // immediate work. |
+ if (!main_thread_only().delayed_incoming_queue.empty() && |
+ main_thread_only().delayed_incoming_queue.begin()->delayed_run_time <= |
+ main_thread_only().time_domain->CreateLazyNow().Now()) { |
return true; |
} |
- return task->enqueue_order() < enqueue_order; |
-} |
- |
-bool TaskQueueImpl::ShouldAutoPumpImmediateQueueLocked( |
- bool should_trigger_wakeup, |
- const Task* previous_task) { |
- if (main_thread_only().pump_policy == PumpPolicy::MANUAL) |
- return false; |
- if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP && |
- (!should_trigger_wakeup || |
- TaskIsOlderThanQueuedImmediateTasksLocked(previous_task))) |
- return false; |
- return true; |
-} |
- |
-bool TaskQueueImpl::ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup, |
- const Task* previous_task) { |
- if (main_thread_only().pump_policy == PumpPolicy::MANUAL) |
- return false; |
- if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP && |
- (!should_trigger_wakeup || |
- TaskIsOlderThanQueuedDelayedTasks(previous_task))) |
- return false; |
- return true; |
+ // Finally tasks on |immediate_incoming_queue| count as immediate work. |
+ base::AutoLock lock(any_thread_lock_); |
+ return !any_thread().immediate_incoming_queue.empty(); |
} |
void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { |
@@ -609,25 +549,18 @@ void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { |
} |
} |
-void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now, |
- bool should_trigger_wakeup, |
- const Task* previous_task) { |
+void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now) { |
if (!main_thread_only().task_queue_manager) |
return; |
- if (!ShouldAutoPumpDelayedQueue(should_trigger_wakeup, previous_task)) |
- return; |
MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); |
TraceQueueSize(false); |
} |
-void TaskQueueImpl::UpdateImmediateWorkQueue(bool should_trigger_wakeup, |
- const Task* previous_task) { |
+void TaskQueueImpl::UpdateImmediateWorkQueue() { |
DCHECK(main_thread_only().immediate_work_queue->Empty()); |
base::AutoLock lock(any_thread_lock_); |
if (!main_thread_only().task_queue_manager) |
return; |
- if (!ShouldAutoPumpImmediateQueueLocked(should_trigger_wakeup, previous_task)) |
- return; |
main_thread_only().immediate_work_queue->SwapLocked( |
any_thread().immediate_incoming_queue); |
@@ -663,56 +596,6 @@ void TaskQueueImpl::TraceQueueSize(bool is_locked) const { |
any_thread_lock_.Release(); |
} |
-void TaskQueueImpl::SetPumpPolicy(PumpPolicy pump_policy) { |
- base::AutoLock lock(any_thread_lock_); |
- if (pump_policy == PumpPolicy::AUTO && |
- any_thread().pump_policy != PumpPolicy::AUTO) { |
- LazyNow lazy_now(main_thread_only().time_domain->CreateLazyNow()); |
- PumpQueueLocked(&lazy_now, true); |
- } |
- any_thread().pump_policy = pump_policy; |
- main_thread_only().pump_policy = pump_policy; |
-} |
- |
-TaskQueue::PumpPolicy TaskQueueImpl::GetPumpPolicy() const { |
- return main_thread_only().pump_policy; |
-} |
- |
-void TaskQueueImpl::PumpQueueLocked(LazyNow* lazy_now, bool may_post_dowork) { |
- TRACE_EVENT1(disabled_by_default_tracing_category_, |
- "TaskQueueImpl::PumpQueueLocked", "queue", name_); |
- TaskQueueManager* task_queue_manager = any_thread().task_queue_manager; |
- if (!task_queue_manager) |
- return; |
- |
- MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); |
- |
- while (!any_thread().immediate_incoming_queue.empty()) { |
- ComparatorQueue::iterator it = |
- any_thread().immediate_incoming_queue.begin(); |
- main_thread_only().immediate_work_queue->Push( |
- std::move(const_cast<Task&>(*it))); |
- any_thread().immediate_incoming_queue.erase(it); |
- } |
- |
- // |immediate_incoming_queue| is now empty so TimeDomain::UpdateQueues no |
- // longer needs to consider this queue for reloading. |
- main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); |
- |
- if (main_thread_only().immediate_work_queue->Empty() && |
- main_thread_only().delayed_work_queue->Empty()) { |
- return; |
- } |
- |
- if (may_post_dowork) |
- task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
-} |
- |
-void TaskQueueImpl::PumpQueue(LazyNow* lazy_now, bool may_post_dowork) { |
- base::AutoLock lock(any_thread_lock_); |
- PumpQueueLocked(lazy_now, may_post_dowork); |
-} |
- |
const char* TaskQueueImpl::GetName() const { |
return name_; |
} |
@@ -731,36 +614,6 @@ TaskQueueImpl::QueuePriority TaskQueueImpl::GetQueuePriority() const { |
} |
// static |
-const char* TaskQueueImpl::PumpPolicyToString( |
- TaskQueue::PumpPolicy pump_policy) { |
- switch (pump_policy) { |
- case TaskQueue::PumpPolicy::AUTO: |
- return "auto"; |
- case TaskQueue::PumpPolicy::AFTER_WAKEUP: |
- return "after_wakeup"; |
- case TaskQueue::PumpPolicy::MANUAL: |
- return "manual"; |
- default: |
- NOTREACHED(); |
- return nullptr; |
- } |
-} |
- |
-// static |
-const char* TaskQueueImpl::WakeupPolicyToString( |
- TaskQueue::WakeupPolicy wakeup_policy) { |
- switch (wakeup_policy) { |
- case TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES: |
- return "can_wake_other_queues"; |
- case TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES: |
- return "dont_wake_other_queues"; |
- default: |
- NOTREACHED(); |
- return nullptr; |
- } |
-} |
- |
-// static |
const char* TaskQueueImpl::PriorityToString(QueuePriority priority) { |
switch (priority) { |
case CONTROL_PRIORITY: |
@@ -784,8 +637,6 @@ void TaskQueueImpl::AsValueInto(base::trace_event::TracedValue* state) const { |
state->SetBoolean("enabled", main_thread_only().is_enabled); |
state->SetString("time_domain_name", |
main_thread_only().time_domain->GetName()); |
- state->SetString("pump_policy", PumpPolicyToString(any_thread().pump_policy)); |
- state->SetString("wakeup_policy", WakeupPolicyToString(wakeup_policy_)); |
bool verbose_tracing_enabled = false; |
TRACE_EVENT_CATEGORY_GROUP_ENABLED( |
disabled_by_default_verbose_tracing_category_, &verbose_tracing_enabled); |
@@ -884,6 +735,96 @@ void TaskQueueImpl::SetBlameContext( |
main_thread_only().blame_context = blame_context; |
} |
+void TaskQueueImpl::InsertFence() { |
+ if (!main_thread_only().task_queue_manager) |
+ return; |
+ |
+ EnqueueOrder previous_fence = main_thread_only().current_fence; |
+ main_thread_only().current_fence = |
+ main_thread_only().task_queue_manager->GetNextSequenceNumber(); |
+ |
+ // Tasks posted after this point will have a strictly higher enqueue order |
+ // and will be blocked from running. |
+ bool task_unblocked = main_thread_only().immediate_work_queue->InsertFence( |
+ main_thread_only().current_fence); |
+ task_unblocked |= main_thread_only().delayed_work_queue->InsertFence( |
+ main_thread_only().current_fence); |
+ |
+ if (!task_unblocked && previous_fence) { |
+ base::AutoLock lock(any_thread_lock_); |
+ if (!any_thread().immediate_incoming_queue.empty() && |
+ any_thread().immediate_incoming_queue.begin()->enqueue_order() > |
+ previous_fence && |
+ any_thread().immediate_incoming_queue.begin()->enqueue_order() < |
+ main_thread_only().current_fence) { |
+ task_unblocked = true; |
+ } |
+ } |
+ |
+ if (main_thread_only().is_enabled && task_unblocked) { |
+ main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
+ FROM_HERE); |
+ } |
+} |
+ |
+void TaskQueueImpl::RemoveFence() { |
+ if (!main_thread_only().task_queue_manager) |
+ return; |
+ |
+ EnqueueOrder previous_fence = main_thread_only().current_fence; |
+ main_thread_only().current_fence = 0; |
+ |
+ bool task_unblocked = main_thread_only().immediate_work_queue->RemoveFence(); |
+ task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence(); |
+ |
+ if (!task_unblocked && previous_fence) { |
+ base::AutoLock lock(any_thread_lock_); |
+ if (!any_thread().immediate_incoming_queue.empty() && |
+ any_thread().immediate_incoming_queue.begin()->enqueue_order() > |
+ previous_fence) { |
+ task_unblocked = true; |
+ } |
+ } |
+ |
+ if (main_thread_only().is_enabled && task_unblocked) { |
+ main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
+ FROM_HERE); |
+ } |
+} |
+ |
+bool TaskQueueImpl::BlockedByFence() const { |
+ if (!main_thread_only().current_fence) |
+ return false; |
+ |
+ if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
+ !main_thread_only().delayed_work_queue->BlockedByFence()) { |
+ return false; |
+ } |
+ |
+ base::AutoLock lock(any_thread_lock_); |
+ if (any_thread().immediate_incoming_queue.empty()) |
+ return true; |
+ |
+ return any_thread().immediate_incoming_queue.begin()->enqueue_order() > |
+ main_thread_only().current_fence; |
+} |
+ |
+bool TaskQueueImpl::BlockedByFenceLocked() const { |
+ if (!main_thread_only().current_fence) |
+ return false; |
+ |
+ if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
+ !main_thread_only().delayed_work_queue->BlockedByFence()) { |
+ return false; |
+ } |
+ |
+ if (any_thread().immediate_incoming_queue.empty()) |
+ return true; |
+ |
+ return any_thread().immediate_incoming_queue.begin()->enqueue_order() > |
+ main_thread_only().current_fence; |
+} |
+ |
// static |
void TaskQueueImpl::QueueAsValueInto(const ComparatorQueue& queue, |
base::trace_event::TracedValue* state) { |