| Index: third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
|
| diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
|
| index fdb9ec552dba08516b56fc49acbfba44accbe987..16dc9089c0f9fe4b5d58cad805e6aa62729d6d50 100644
|
| --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
|
| +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
|
| @@ -147,18 +147,35 @@ void TaskQueueManager::UnregisterTaskQueue(
|
| queues_.erase(task_queue);
|
|
|
| selector_.RemoveQueue(task_queue.get());
|
| +
|
| + {
|
| + base::AutoLock lock(any_thread_lock_);
|
| + any_thread().has_incoming_immediate_work.erase(task_queue.get());
|
| + }
|
| }
|
|
|
| -void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) {
|
| +void TaskQueueManager::ReloadEmptyWorkQueues(
|
| + const std::unordered_set<internal::TaskQueueImpl*>& queues_to_reload)
|
| + const {
|
| + // There are two cases where a queue needs reloading. First, it might be
|
| + // completely empty and we've just posted a task (this method handles that
|
| + // case). Secondly if the work queue becomes empty in when calling
|
| + // WorkQueue::TakeTaskFromWorkQueue (handled there).
|
| + for (internal::TaskQueueImpl* queue : queues_to_reload) {
|
| + queue->ReloadImmediateWorkQueueIfEmpty();
|
| + }
|
| +}
|
| +
|
| +void TaskQueueManager::WakeupReadyDelayedQueues(LazyNow* lazy_now) {
|
| TRACE_EVENT0(disabled_by_default_tracing_category_,
|
| - "TaskQueueManager::UpdateWorkQueues");
|
| + "TaskQueueManager::WakeupReadyDelayedQueues");
|
|
|
| for (TimeDomain* time_domain : time_domains_) {
|
| if (time_domain == real_time_domain_.get()) {
|
| - time_domain->UpdateWorkQueues(lazy_now);
|
| + time_domain->WakeupReadyDelayedQueues(lazy_now);
|
| } else {
|
| LazyNow time_domain_lazy_now = time_domain->CreateLazyNow();
|
| - time_domain->UpdateWorkQueues(&time_domain_lazy_now);
|
| + time_domain->WakeupReadyDelayedQueues(&time_domain_lazy_now);
|
| }
|
| }
|
| }
|
| @@ -169,6 +186,37 @@ void TaskQueueManager::OnBeginNestedMessageLoop() {
|
| delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_);
|
| }
|
|
|
| +void TaskQueueManager::OnQueueHasIncomingImmediateWork(
|
| + internal::TaskQueueImpl* queue,
|
| + bool queue_is_blocked) {
|
| + bool on_main_thread = delegate_->BelongsToCurrentThread();
|
| +
|
| + {
|
| + base::AutoLock lock(any_thread_lock_);
|
| + any_thread().has_incoming_immediate_work.insert(queue);
|
| +
|
| + if (queue_is_blocked)
|
| + return;
|
| +
|
| + // De-duplicate DoWork posts.
|
| + if (on_main_thread) {
|
| + if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second)
|
| + return;
|
| + } else {
|
| + if (any_thread().other_thread_pending_wakeup)
|
| + return;
|
| + any_thread().other_thread_pending_wakeup = true;
|
| + }
|
| + }
|
| +
|
| + if (on_main_thread) {
|
| + delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_);
|
| + } else {
|
| + delegate_->PostTask(FROM_HERE,
|
| + from_other_thread_immediate_do_work_closure_);
|
| + }
|
| +}
|
| +
|
| void TaskQueueManager::MaybeScheduleImmediateWork(
|
| const tracked_objects::Location& from_here) {
|
| bool on_main_thread = delegate_->BelongsToCurrentThread();
|
| @@ -237,9 +285,20 @@ void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) {
|
| queues_to_delete_.clear();
|
|
|
| LazyNow lazy_now(real_time_domain()->CreateLazyNow());
|
| - UpdateWorkQueues(&lazy_now);
|
| + WakeupReadyDelayedQueues(&lazy_now);
|
|
|
| for (int i = 0; i < work_batch_size_; i++) {
|
| + std::unordered_set<internal::TaskQueueImpl*> queues_to_reload;
|
| +
|
| + {
|
| + base::AutoLock lock(any_thread_lock_);
|
| + std::swap(queues_to_reload, any_thread().has_incoming_immediate_work);
|
| + }
|
| +
|
| + // It's important we call ReloadEmptyWorkQueues out side of the lock to
|
| + // avoid a lock order inversion.
|
| + ReloadEmptyWorkQueues(queues_to_reload);
|
| +
|
| internal::WorkQueue* work_queue;
|
| if (!SelectWorkQueueToService(&work_queue))
|
| break;
|
| @@ -260,7 +319,7 @@ void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) {
|
|
|
| lazy_now = time_after_task.is_null() ? real_time_domain()->CreateLazyNow()
|
| : LazyNow(time_after_task);
|
| - UpdateWorkQueues(&lazy_now);
|
| + WakeupReadyDelayedQueues(&lazy_now);
|
|
|
| // Only run a single task per batch in nested run loops so that we can
|
| // properly exit the nested loop when someone calls RunLoop::Quit().
|
| @@ -289,6 +348,18 @@ void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) {
|
|
|
| base::Optional<base::TimeDelta> TaskQueueManager::ComputeDelayTillNextTask(
|
| LazyNow* lazy_now) {
|
| + DCHECK(main_thread_checker_.CalledOnValidThread());
|
| +
|
| + std::unordered_set<internal::TaskQueueImpl*> queues_to_reload;
|
| + {
|
| + base::AutoLock lock(any_thread_lock_);
|
| + std::swap(queues_to_reload, any_thread().has_incoming_immediate_work);
|
| + }
|
| +
|
| + // It's important we call ReloadEmptyWorkQueues out side of the lock to
|
| + // avoid a lock order inversion.
|
| + ReloadEmptyWorkQueues(queues_to_reload);
|
| +
|
| // If the selector has non-empty queues we trivially know there is immediate
|
| // work to be done.
|
| if (!selector_.EnabledWorkQueuesEmpty())
|
| @@ -505,6 +576,15 @@ TaskQueueManager::AsValueWithSelectorResult(
|
| for (auto* time_domain : time_domains_)
|
| time_domain->AsValueInto(state.get());
|
| state->EndArray();
|
| + {
|
| + base::AutoLock lock(any_thread_lock_);
|
| + state->BeginArray("has_incoming_immediate_work");
|
| + for (internal::TaskQueueImpl* task_queue :
|
| + any_thread().has_incoming_immediate_work) {
|
| + state->AppendString(task_queue->GetName());
|
| + }
|
| + state->EndArray();
|
| + }
|
| return std::move(state);
|
| }
|
|
|
|
|