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 a0bc14200139e176ee03b6dccefa0d8a29270d67..7ef94420f8acce312fe2bd791d89714d75d30aa1 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 |
@@ -154,8 +154,11 @@ TaskQueueImpl::MainThreadOnly::MainThreadOnly( |
TimeDomain* time_domain) |
: task_queue_manager(task_queue_manager), |
time_domain(time_domain), |
- delayed_work_queue(new WorkQueue(task_queue, "delayed")), |
- immediate_work_queue(new WorkQueue(task_queue, "immediate")), |
+ delayed_work_queue( |
+ new WorkQueue(task_queue, "delayed", WorkQueue::QueueType::DELAYED)), |
+ immediate_work_queue(new WorkQueue(task_queue, |
+ "immediate", |
+ WorkQueue::QueueType::IMMEDIATE)), |
set_index(0), |
is_enabled_refcount(0), |
voter_refcount(0), |
@@ -183,7 +186,6 @@ void TaskQueueImpl::UnregisterTaskQueue() { |
} |
bool TaskQueueImpl::RunsTasksOnCurrentThread() const { |
- base::AutoLock lock(any_thread_lock_); |
return base::PlatformThread::CurrentId() == thread_id_; |
} |
@@ -325,19 +327,17 @@ void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked( |
base::TimeTicks desired_run_time, |
EnqueueOrder sequence_number, |
bool nestable) { |
- if (any_thread().immediate_incoming_queue.empty()) |
- any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); |
// 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 (IsQueueEnabled() && !BlockedByFenceLocked()) |
- any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
- } else { |
- any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
- } |
+ // There's no point posting a DoWork for a blocked or disabled queue, |
+ // although we can only determine that on the main thread. |
+ bool ensure_do_work_posted = |
+ !RunsTasksOnCurrentThread() || |
+ (IsQueueEnabled() && !main_thread_only().current_fence); |
+ any_thread().task_queue_manager->OnQueueHasIncomingImmediateWork( |
+ this, ensure_do_work_posted); |
+ any_thread().time_domain->OnQueueHasImmediateWork(this); |
} |
any_thread().immediate_incoming_queue.emplace_back( |
posted_from, task, desired_run_time, sequence_number, nestable, |
@@ -347,6 +347,20 @@ void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked( |
TraceQueueSize(true); |
} |
+void TaskQueueImpl::ReloadImmediateWorkQueueIfEmpty() { |
+ if (!main_thread_only().immediate_work_queue->Empty()) |
+ return; |
+ |
+ main_thread_only().immediate_work_queue->ReloadEmptyImmediateQueue(); |
+} |
+ |
+WTF::Deque<TaskQueueImpl::Task> TaskQueueImpl::TakeImmediateIncomingQueue() { |
+ base::AutoLock lock(any_thread_lock_); |
+ WTF::Deque<TaskQueueImpl::Task> queue; |
+ queue.swap(any_thread().immediate_incoming_queue); |
+ return queue; |
+} |
+ |
bool TaskQueueImpl::IsEmpty() const { |
if (!main_thread_only().delayed_work_queue->Empty() || |
!main_thread_only().delayed_incoming_queue.empty() || |
@@ -396,7 +410,8 @@ base::Optional<base::TimeTicks> TaskQueueImpl::GetNextScheduledWakeUp() { |
return main_thread_only().delayed_incoming_queue.top().delayed_run_time; |
} |
-void TaskQueueImpl::WakeUpForDelayedWork(LazyNow* lazy_now) { |
+base::Optional<base::TimeTicks> TaskQueueImpl::WakeUpForDelayedWork( |
+ LazyNow* lazy_now) { |
// Enqueue all delayed tasks that should be running now, skipping any that |
// have been canceled. |
while (!main_thread_only().delayed_incoming_queue.empty()) { |
@@ -415,25 +430,10 @@ void TaskQueueImpl::WakeUpForDelayedWork(LazyNow* lazy_now) { |
} |
// Make sure the next wake up is scheduled. |
- if (!main_thread_only().delayed_incoming_queue.empty()) { |
- main_thread_only().time_domain->ScheduleDelayedWork( |
- this, main_thread_only().delayed_incoming_queue.top().delayed_run_time, |
- lazy_now->Now()); |
- } |
-} |
- |
-bool TaskQueueImpl::MaybeUpdateImmediateWorkQueues() { |
- if (!main_thread_only().task_queue_manager) |
- return false; |
- |
- if (!main_thread_only().immediate_work_queue->Empty()) |
- return true; |
+ if (!main_thread_only().delayed_incoming_queue.empty()) |
+ return main_thread_only().delayed_incoming_queue.top().delayed_run_time; |
- base::AutoLock lock(any_thread_lock_); |
- main_thread_only().immediate_work_queue->SwapLocked( |
- any_thread().immediate_incoming_queue); |
- // |immediate_work_queue| is now empty so updates are no longer required. |
- return false; |
+ return base::Optional<base::TimeTicks>(); |
} |
void TaskQueueImpl::TraceQueueSize(bool is_locked) const { |
@@ -576,10 +576,13 @@ void TaskQueueImpl::SetTimeDomain(TimeDomain* time_domain) { |
any_thread().time_domain = time_domain; |
} |
- // We rely here on TimeDomain::MigrateQueue being thread-safe to use with |
- // TimeDomain::Register/UnregisterAsUpdatableTaskQueue. |
- main_thread_only().time_domain->MigrateQueue(this, time_domain); |
+ |
+ base::TimeTicks wake_up_time = |
+ main_thread_only().time_domain->MigrateQueue(this, time_domain); |
main_thread_only().time_domain = time_domain; |
+ |
+ if (!wake_up_time.is_null()) |
+ time_domain->ScheduleDelayedWork(this, wake_up_time, time_domain->Now()); |
} |
TimeDomain* TaskQueueImpl::GetTimeDomain() const { |
@@ -672,19 +675,20 @@ bool TaskQueueImpl::BlockedByFence() const { |
main_thread_only().current_fence; |
} |
-bool TaskQueueImpl::BlockedByFenceLocked() const { |
- if (!main_thread_only().current_fence) |
+bool TaskQueueImpl::ImmediateTaskCouldRun() const { |
+ if (!IsQueueEnabled()) |
return false; |
- if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
- !main_thread_only().delayed_work_queue->BlockedByFence()) { |
- return false; |
- } |
+ if (!main_thread_only().current_fence) |
+ return true; |
+ base::AutoLock lock(any_thread_lock_); |
+ // If |immediate_incoming_queue| is empty then any task posted is guaranteed |
+ // to be blocked by the fence. |
if (any_thread().immediate_incoming_queue.empty()) |
- return true; |
+ return false; |
- return any_thread().immediate_incoming_queue.front().enqueue_order() > |
+ return any_thread().immediate_incoming_queue.front().enqueue_order() < |
main_thread_only().current_fence; |
} |
@@ -799,8 +803,8 @@ void TaskQueueImpl::EnableOrDisableWithSelector(bool enable) { |
return; |
if (enable) { |
- // Note it's the job of the selector to tell the TaskQueueManager if |
- // a DoWork needs posting. |
+ // Note the selector calls TaskQueueManager::OnTaskQueueEnabled which posts |
+ // a DoWork if needed. |
main_thread_only().task_queue_manager->selector_.EnableQueue(this); |
} else { |
main_thread_only().task_queue_manager->selector_.DisableQueue(this); |
@@ -821,19 +825,33 @@ void TaskQueueImpl::SweepCanceledDelayedTasks(base::TimeTicks now) { |
base::TimeTicks first_task_runtime = |
main_thread_only().delayed_incoming_queue.top().delayed_run_time; |
- // TODO(alexclarke): Let this remove all tasks once the DoWork refactor has |
- // landed. |
+ // Remove canceled tasks. |
std::priority_queue<Task> remaining_tasks; |
while (!main_thread_only().delayed_incoming_queue.empty()) { |
- if (!main_thread_only().delayed_incoming_queue.top().task.IsCancelled() || |
- main_thread_only().delayed_incoming_queue.top().delayed_run_time == |
- first_task_runtime) { |
+ if (!main_thread_only().delayed_incoming_queue.top().task.IsCancelled()) { |
remaining_tasks.push(std::move( |
const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()))); |
} |
main_thread_only().delayed_incoming_queue.pop(); |
} |
+ |
main_thread_only().delayed_incoming_queue = std::move(remaining_tasks); |
+ |
+ // Re-schedule delayed call to WakeUpForDelayedWork if needed. |
+ if (main_thread_only().delayed_incoming_queue.empty()) { |
+ main_thread_only().time_domain->CancelDelayedWork(this); |
+ } else if (first_task_runtime != |
+ main_thread_only().delayed_incoming_queue.top().delayed_run_time) { |
+ main_thread_only().time_domain->ScheduleDelayedWork( |
+ this, main_thread_only().delayed_incoming_queue.top().delayed_run_time, |
+ main_thread_only().time_domain->Now()); |
+ } |
+} |
+ |
+void TaskQueueImpl::PushImmediateIncomingTaskForTest( |
+ TaskQueueImpl::Task&& task) { |
+ base::AutoLock lock(any_thread_lock_); |
+ any_thread().immediate_incoming_queue.push_back(std::move(task)); |
} |
} // namespace internal |