Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(967)

Unified Diff: third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc

Issue 2653643002: Move has_incoming_immediate_work to the TaskQueueManager (Closed)
Patch Set: Don't try to be quite so clever in TaskQueueManager::ComputeDelayTillNextTask Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
}

Powered by Google App Engine
This is Rietveld 408576698