Chromium Code Reviews| 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..cb80df6bdc14444c0a19420030066840c47ccbd9 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,33 @@ 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::ReloadEmptyWorkQueues( |
| + const std::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 |
|
Sami
2017/01/24 14:52:40
Secondly...? :)
alex clarke (OOO till 29th)
2017/01/24 15:28:14
Done.
|
| + for (internal::TaskQueueImpl* queue : queues_to_reload) { |
| + queue->ReloadImmediateWorkQueueIfEmpty(); |
| + } |
| } |
| -void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) { |
| +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 +184,37 @@ void TaskQueueManager::OnBeginNestedMessageLoop() { |
| delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); |
| } |
| +void TaskQueueManager::OnQueueHasIncomingImmediateWork( |
| + internal::TaskQueueImpl* queue, |
| + bool ensure_do_work_posted) { |
| + bool on_main_thread = delegate_->BelongsToCurrentThread(); |
| + |
| + { |
| + base::AutoLock lock(any_thread_lock_); |
| + any_thread().has_incoming_immediate_work.insert(queue); |
| + |
| + if (!ensure_do_work_posted) |
| + 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 +283,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::set<internal::TaskQueueImpl*> queues_to_reload; |
|
Sami
2017/01/24 14:52:40
Probably doesn't make a huge difference, but unord
alex clarke (OOO till 29th)
2017/01/24 15:28:14
I guess.
|
| + |
| + { |
| + 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 +317,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,11 +346,26 @@ 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()); |
| + |
| // If the selector has non-empty queues we trivially know there is immediate |
| // work to be done. |
| if (!selector_.EnabledWorkQueuesEmpty()) |
| return base::TimeDelta(); |
| + { |
| + base::AutoLock lock(any_thread_lock_); |
|
Sami
2017/01/24 14:52:40
Any lock inversion issues here? Basically I think
alex clarke (OOO till 29th)
2017/01/24 15:28:14
Yeah actually that could be one. Can probably get
alex clarke (OOO till 29th)
2017/01/24 15:29:11
Actually on second thoughts I think I'm trying to
|
| + // If we have incoming immediate work for any queue able to run, we know |
| + // there is immediate work to be done. |
| + for (internal::TaskQueueImpl* queue : |
| + any_thread().has_incoming_immediate_work) { |
| + // Note when posted ImmediateTaskCouldRun would have returned true but |
| + // conditions may have changed since then. |
| + if (queue->ImmediateTaskCouldRun()) |
| + return base::TimeDelta(); |
| + } |
| + } |
| + |
| // Otherwise we need to find the shortest delay, if any. |
| base::Optional<base::TimeDelta> next_continuation; |
| for (TimeDomain* time_domain : time_domains_) { |
| @@ -505,6 +577,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); |
| } |