| 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(
|
|
|