Commit ca263da9 authored by Eric Seckler's avatar Eric Seckler Committed by Commit Bot

blink: Fix a virtual time deadlock situation

It's possible that we advance virtual time past the time of the next
task scheduled to execute. In that case,
AutoAdvancingVirtualTimeDomain::DelayTillNextTask should instruct the
TaskQueueManager to run the task immediately.

Bug: 777763
Change-Id: I90a2501df05334d9971e8518717bacd9ae95693d
Reviewed-on: https://chromium-review.googlesource.com/982113
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Reviewed-by: default avatarSami Kyöstilä <skyostil@chromium.org>
Cr-Commit-Position: refs/heads/master@{#546202}
parent 5eacb505
...@@ -46,7 +46,15 @@ AutoAdvancingVirtualTimeDomain::~AutoAdvancingVirtualTimeDomain() { ...@@ -46,7 +46,15 @@ AutoAdvancingVirtualTimeDomain::~AutoAdvancingVirtualTimeDomain() {
base::Optional<base::TimeDelta> base::Optional<base::TimeDelta>
AutoAdvancingVirtualTimeDomain::DelayTillNextTask(LazyNow* lazy_now) { AutoAdvancingVirtualTimeDomain::DelayTillNextTask(LazyNow* lazy_now) {
base::TimeTicks run_time; base::TimeTicks run_time;
if (!can_advance_virtual_time_ || !NextScheduledRunTime(&run_time)) if (!NextScheduledRunTime(&run_time))
return base::nullopt;
// We may have advanced virtual time past the next task when a
// WebScopedVirtualTimePauser unpauses.
if (run_time <= Now())
return base::TimeDelta();
if (!can_advance_virtual_time_)
return base::nullopt; return base::nullopt;
if (MaybeAdvanceVirtualTime(run_time)) { if (MaybeAdvanceVirtualTime(run_time)) {
...@@ -89,7 +97,6 @@ void AutoAdvancingVirtualTimeDomain::SetMaxVirtualTimeTaskStarvationCount( ...@@ -89,7 +97,6 @@ void AutoAdvancingVirtualTimeDomain::SetMaxVirtualTimeTaskStarvationCount(
void AutoAdvancingVirtualTimeDomain::SetVirtualTimeFence( void AutoAdvancingVirtualTimeDomain::SetVirtualTimeFence(
base::TimeTicks virtual_time_fence) { base::TimeTicks virtual_time_fence) {
DCHECK_GE(virtual_time_fence, virtual_time_fence);
virtual_time_fence_ = virtual_time_fence; virtual_time_fence_ = virtual_time_fence;
if (!requested_next_virtual_time_.is_null()) if (!requested_next_virtual_time_.is_null())
MaybeAdvanceVirtualTime(requested_next_virtual_time_); MaybeAdvanceVirtualTime(requested_next_virtual_time_);
......
...@@ -225,6 +225,24 @@ TEST_F(AutoAdvancingVirtualTimeDomainTest, BaseTimeTicksOverriden) { ...@@ -225,6 +225,24 @@ TEST_F(AutoAdvancingVirtualTimeDomainTest, BaseTimeTicksOverriden) {
EXPECT_EQ(base::TimeTicks::Now(), initial_time + delay); EXPECT_EQ(base::TimeTicks::Now(), initial_time + delay);
} }
TEST_F(AutoAdvancingVirtualTimeDomainTest,
DelayTillNextTaskHandlesPastRunTime) {
base::TimeTicks initial_time = clock_.NowTicks();
// Post a task for t+10ms.
bool task_run = false;
task_queue_->PostDelayedTask(FROM_HERE, base::BindOnce(NopTask, &task_run),
base::TimeDelta::FromMilliseconds(10));
// Advance virtual time past task time to t+100ms.
auto_advancing_time_domain_->MaybeAdvanceVirtualTime(
initial_time + base::TimeDelta::FromMilliseconds(100));
// Task at t+10ms should be run immediately.
EXPECT_EQ(base::TimeDelta(),
auto_advancing_time_domain_->DelayTillNextTask(nullptr));
}
} // namespace auto_advancing_virtual_time_domain_unittest } // namespace auto_advancing_virtual_time_domain_unittest
} // namespace scheduler } // namespace scheduler
} // namespace blink } // namespace blink
...@@ -548,6 +548,77 @@ TEST_F(PageSchedulerImplTest, ...@@ -548,6 +548,77 @@ TEST_F(PageSchedulerImplTest,
EXPECT_TRUE(scheduler_->VirtualTimeAllowedToAdvance()); EXPECT_TRUE(scheduler_->VirtualTimeAllowedToAdvance());
} }
namespace {
void RecordVirtualTime(RendererSchedulerImpl* scheduler, base::TimeTicks* out) {
*out = scheduler->GetVirtualTimeDomain()->Now();
}
void PauseAndUnpauseVirtualTime(RendererSchedulerImpl* scheduler,
FrameSchedulerImpl* frame_scheduler,
base::TimeTicks* paused,
base::TimeTicks* unpaused) {
*paused = scheduler->GetVirtualTimeDomain()->Now();
{
WebScopedVirtualTimePauser virtual_time_pauser =
frame_scheduler->CreateWebScopedVirtualTimePauser(
WebScopedVirtualTimePauser::VirtualTaskDuration::kNonInstant);
virtual_time_pauser.PauseVirtualTime(true);
}
*unpaused = scheduler->GetVirtualTimeDomain()->Now();
}
} // namespace
TEST_F(PageSchedulerImplTest,
WebScopedVirtualTimePauserWithInterleavedTasks_DETERMINISTIC_LOADING) {
// Make task queue manager ask the virtual time domain for the next task delay
// after each task.
scheduler_->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting(1);
page_scheduler_->EnableVirtualTime();
page_scheduler_->SetVirtualTimePolicy(
VirtualTimePolicy::kDeterministicLoading);
base::TimeTicks initial_virtual_time =
scheduler_->GetVirtualTimeDomain()->Now();
base::TimeTicks time_paused;
base::TimeTicks time_unpaused;
base::TimeTicks time_second_task;
std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
page_scheduler_->CreateFrameSchedulerImpl(
nullptr, FrameScheduler::FrameType::kSubframe);
// Pauses and unpauses virtual time, thereby advancing virtual time by an
// additional 10ms due to WebScopedVirtualTimePauser's delay.
ThrottleableTaskRunner()->PostDelayedTask(
FROM_HERE,
WTF::Bind(&PauseAndUnpauseVirtualTime, WTF::Unretained(scheduler_.get()),
WTF::Unretained(frame_scheduler.get()),
WTF::Unretained(&time_paused), WTF::Unretained(&time_unpaused)),
base::TimeDelta::FromMilliseconds(3));
// Will run after the first task has advanced virtual time past 5ms.
ThrottleableTaskRunner()->PostDelayedTask(
FROM_HERE,
WTF::Bind(&RecordVirtualTime, WTF::Unretained(scheduler_.get()),
WTF::Unretained(&time_second_task)),
base::TimeDelta::FromMilliseconds(5));
mock_task_runner_->RunUntilIdle();
EXPECT_EQ(time_paused,
initial_virtual_time + base::TimeDelta::FromMilliseconds(3));
EXPECT_EQ(time_unpaused,
initial_virtual_time + base::TimeDelta::FromMilliseconds(13));
EXPECT_EQ(time_second_task,
initial_virtual_time + base::TimeDelta::FromMilliseconds(13));
}
TEST_F(PageSchedulerImplTest, TEST_F(PageSchedulerImplTest,
MultipleWebScopedVirtualTimePausers_DETERMINISTIC_LOADING) { MultipleWebScopedVirtualTimePausers_DETERMINISTIC_LOADING) {
page_scheduler_->SetVirtualTimePolicy( page_scheduler_->SetVirtualTimePolicy(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment