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 e42fee10c09e0aa1542725e07936804dca855cc6..49fd2f89237d79afa9f7c8a525b55e28f2b0f0fa 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 |
@@ -230,10 +230,13 @@ void TaskQueueManager::MaybeScheduleImmediateWorkLocked( |
void TaskQueueManager::MaybeScheduleDelayedWork( |
const tracked_objects::Location& from_here, |
+ TimeDomain* requesting_time_domain, |
base::TimeTicks now, |
- base::TimeDelta delay) { |
+ base::TimeTicks run_time) { |
DCHECK(main_thread_checker_.CalledOnValidThread()); |
- DCHECK_GE(delay, base::TimeDelta()); |
+ // Make sure we don't cancel another TimeDomain's wakeup. |
+ DCHECK(!next_delayed_do_work_ || |
+ next_delayed_do_work_.time_domain() == requesting_time_domain); |
{ |
base::AutoLock lock(any_thread_lock_); |
@@ -247,22 +250,35 @@ void TaskQueueManager::MaybeScheduleDelayedWork( |
} |
} |
- // De-duplicate DoWork posts. |
- base::TimeTicks run_time = now + delay; |
- if (next_scheduled_delayed_do_work_time_ <= run_time && |
- !next_scheduled_delayed_do_work_time_.is_null()) |
+ // If there's a delayed DoWork scheduled to run sooner, we don't need to do |
+ // anything because DoWork will post a delayed continuation as needed. |
+ if (next_delayed_do_work_ && next_delayed_do_work_.run_time() <= run_time) |
return; |
+ cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); |
+ |
+ base::TimeDelta delay = std::max(base::TimeDelta(), run_time - now); |
TRACE_EVENT1(disabled_by_default_tracing_category_, |
"TaskQueueManager::MaybeScheduleDelayedWork::PostDelayedTask", |
"delay_ms", delay.InMillisecondsF()); |
cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); |
- next_scheduled_delayed_do_work_time_ = run_time; |
+ next_delayed_do_work_ = NextDelayedDoWork(run_time, requesting_time_domain); |
delegate_->PostDelayedTask( |
from_here, cancelable_delayed_do_work_closure_.callback(), delay); |
} |
+void TaskQueueManager::CancelDelayedWork(TimeDomain* requesting_time_domain, |
+ base::TimeTicks run_time) { |
+ DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ if (next_delayed_do_work_.run_time() != run_time) |
+ return; |
+ |
+ DCHECK_EQ(next_delayed_do_work_.time_domain(), requesting_time_domain); |
+ cancelable_delayed_do_work_closure_.Cancel(); |
+ next_delayed_do_work_.Clear(); |
+} |
+ |
void TaskQueueManager::DoWork(bool delayed) { |
DCHECK(main_thread_checker_.CalledOnValidThread()); |
TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", "delayed", |
@@ -274,10 +290,9 @@ void TaskQueueManager::DoWork(bool delayed) { |
queues_to_delete_.clear(); |
// This must be done before running any tasks because they could invoke a |
- // nested message loop and we risk having a stale |
- // |next_scheduled_delayed_do_work_time_|. |
+ // nested message loop and we risk having a stale |next_delayed_do_work_|. |
if (delayed) |
- next_scheduled_delayed_do_work_time_ = base::TimeTicks(); |
+ next_delayed_do_work_.Clear(); |
for (int i = 0; i < work_batch_size_; i++) { |
IncomingImmediateWorkMap queues_to_reload; |
@@ -339,7 +354,7 @@ void TaskQueueManager::DoWork(bool delayed) { |
{ |
MoveableAutoLock lock(any_thread_lock_); |
- base::Optional<base::TimeDelta> next_delay = |
+ base::Optional<NextTaskDelay> next_delay = |
ComputeDelayTillNextTaskLocked(&lazy_now); |
any_thread().do_work_running_count--; |
@@ -353,11 +368,10 @@ void TaskQueueManager::DoWork(bool delayed) { |
} |
void TaskQueueManager::PostDoWorkContinuationLocked( |
- base::Optional<base::TimeDelta> next_delay, |
+ base::Optional<NextTaskDelay> next_delay, |
LazyNow* lazy_now, |
MoveableAutoLock&& lock) { |
DCHECK(main_thread_checker_.CalledOnValidThread()); |
- base::TimeDelta delay; |
{ |
MoveableAutoLock auto_lock(std::move(lock)); |
@@ -365,8 +379,8 @@ void TaskQueueManager::PostDoWorkContinuationLocked( |
// If there are no tasks left then we don't need to post a continuation. |
if (!next_delay) { |
// If there's a pending delayed DoWork, cancel it because it's not needed. |
- if (!next_scheduled_delayed_do_work_time_.is_null()) { |
- next_scheduled_delayed_do_work_time_ = base::TimeTicks(); |
+ if (next_delayed_do_work_) { |
+ next_delayed_do_work_.Clear(); |
cancelable_delayed_do_work_closure_.Cancel(); |
} |
return; |
@@ -376,42 +390,37 @@ void TaskQueueManager::PostDoWorkContinuationLocked( |
if (any_thread().immediate_do_work_posted_count > 0) |
return; |
- delay = next_delay.value(); |
- |
- // This isn't supposed to happen, but in case it does convert to |
- // non-delayed. |
- if (delay < base::TimeDelta()) |
- delay = base::TimeDelta(); |
- |
- if (delay.is_zero()) { |
+ if (next_delay->delay() <= base::TimeDelta()) { |
// If a delayed DoWork is pending then we don't need to post a |
// continuation because it should run immediately. |
- if (!next_scheduled_delayed_do_work_time_.is_null() && |
- next_scheduled_delayed_do_work_time_ <= lazy_now->Now()) { |
+ if (next_delayed_do_work_ && |
+ next_delayed_do_work_.run_time() <= lazy_now->Now()) { |
return; |
} |
any_thread().immediate_do_work_posted_count++; |
- } else { |
- base::TimeTicks run_time = lazy_now->Now() + delay; |
- if (next_scheduled_delayed_do_work_time_ == run_time) |
- return; |
- |
- next_scheduled_delayed_do_work_time_ = run_time; |
} |
} |
// We avoid holding |any_thread_lock_| while posting the task. |
- if (delay.is_zero()) { |
+ if (next_delay->delay() <= base::TimeDelta()) { |
delegate_->PostTask(FROM_HERE, immediate_do_work_closure_); |
} else { |
+ base::TimeTicks run_time = lazy_now->Now() + next_delay->delay(); |
+ |
+ if (next_delayed_do_work_.run_time() == run_time) |
+ return; |
+ |
+ next_delayed_do_work_ = |
+ NextDelayedDoWork(run_time, next_delay->time_domain()); |
cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); |
- delegate_->PostDelayedTask( |
- FROM_HERE, cancelable_delayed_do_work_closure_.callback(), delay); |
+ delegate_->PostDelayedTask(FROM_HERE, |
+ cancelable_delayed_do_work_closure_.callback(), |
+ next_delay->delay()); |
} |
} |
-base::Optional<base::TimeDelta> |
+base::Optional<TaskQueueManager::NextTaskDelay> |
TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) { |
DCHECK(main_thread_checker_.CalledOnValidThread()); |
@@ -420,27 +429,32 @@ TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) { |
// check is equavalent to calling ReloadEmptyWorkQueues first. |
for (const auto& pair : any_thread().has_incoming_immediate_work) { |
if (pair.first->CouldTaskRun(pair.second)) |
- return base::TimeDelta(); |
+ return NextTaskDelay(); |
} |
// If the selector has non-empty queues we trivially know there is immediate |
// work to be done. |
if (!selector_.EnabledWorkQueuesEmpty()) |
- return base::TimeDelta(); |
+ return NextTaskDelay(); |
// Otherwise we need to find the shortest delay, if any. NB we don't need to |
// call WakeupReadyDelayedQueues because it's assumed DelayTillNextTask will |
// return base::TimeDelta>() if the delayed task is due to run now. |
- base::Optional<base::TimeDelta> next_continuation; |
+ base::Optional<NextTaskDelay> delay_till_next_task; |
for (TimeDomain* time_domain : time_domains_) { |
- base::Optional<base::TimeDelta> continuation = |
+ base::Optional<base::TimeDelta> delay = |
time_domain->DelayTillNextTask(lazy_now); |
- if (!continuation) |
+ if (!delay) |
continue; |
- if (!next_continuation || next_continuation.value() > continuation.value()) |
- next_continuation = continuation; |
+ |
+ NextTaskDelay task_delay = (delay.value() == base::TimeDelta()) |
+ ? NextTaskDelay() |
+ : NextTaskDelay(delay.value(), time_domain); |
+ |
+ if (!delay_till_next_task || delay_till_next_task > task_delay) |
+ delay_till_next_task = task_delay; |
} |
- return next_continuation; |
+ return delay_till_next_task; |
} |
bool TaskQueueManager::SelectWorkQueueToService( |