Commit af790bba authored by Alex Clarke's avatar Alex Clarke Committed by Commit Bot

Advance virtual time via SequencedTaskSource

This is necessary for using SequenceManager inside
ScopedTaskEnvironment.  It also makes Virtual Time a bit
cleaner from an interface PoV.

Bug: 863341, 891670
Change-Id: Iaa8300b6c4b2f889b4cfe185959e3a280730636d
Reviewed-on: https://chromium-review.googlesource.com/c/1329969
Commit-Queue: Alex Clarke <alexclarke@chromium.org>
Reviewed-by: default avatarSami Kyöstilä <skyostil@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607254}
parent 55c56063
......@@ -39,6 +39,10 @@ Optional<TimeDelta> RealTimeDomain::DelayTillNextTask(LazyNow* lazy_now) {
return delay;
}
bool RealTimeDomain::MaybeFastForwardToNextTask() {
return false;
}
const char* RealTimeDomain::GetName() const {
return "RealTimeDomain";
}
......
......@@ -22,6 +22,7 @@ class BASE_EXPORT RealTimeDomain : public TimeDomain {
LazyNow CreateLazyNow() const override;
TimeTicks Now() const override;
Optional<TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
bool MaybeFastForwardToNextTask() override;
protected:
const char* GetName() const override;
......
......@@ -515,6 +515,15 @@ bool SequenceManagerImpl::HasPendingHighResolutionTasks() {
return false;
}
bool SequenceManagerImpl::OnSystemIdle() {
bool have_work_to_do = false;
for (TimeDomain* time_domain : main_thread_only().time_domains) {
if (time_domain->MaybeFastForwardToNextTask())
have_work_to_do = true;
};
return have_work_to_do;
}
void SequenceManagerImpl::WillQueueTask(Task* pending_task) {
controller_->WillQueueTask(pending_task);
}
......
......@@ -131,6 +131,7 @@ class BASE_EXPORT SequenceManagerImpl
void DidRunTask() override;
TimeDelta DelayTillNextTask(LazyNow* lazy_now) const override;
bool HasPendingHighResolutionTasks() override;
bool OnSystemIdle() override;
// Methods needed for MessageLoopCurrent support.
// TOOD(alexclarke): Introduce MessageLoopBase and make SequenceManagerImpl
......
......@@ -34,6 +34,11 @@ class SequencedTaskSource {
// Return true if there are any pending tasks in the task source which require
// high resolution timing.
virtual bool HasPendingHighResolutionTasks() = 0;
// Called when we have run out of immediate work. If more immediate work
// becomes available as a result of any processing done by this callback,
// return true to schedule a future DoWork.
virtual bool OnSystemIdle() = 0;
};
} // namespace internal
......
......@@ -28,6 +28,10 @@ Optional<TimeDelta> MockTimeDomain::DelayTillNextTask(LazyNow* lazy_now) {
return nullopt;
}
bool MockTimeDomain::MaybeFastForwardToNextTask() {
return false;
}
void MockTimeDomain::SetNextDelayedDoWork(LazyNow* lazy_now,
TimeTicks run_time) {}
......
......@@ -24,6 +24,7 @@ class MockTimeDomain : public TimeDomain {
TimeTicks Now() const override;
Optional<TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
void SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) override;
bool MaybeFastForwardToNextTask() override;
const char* GetName() const override;
private:
......
......@@ -229,13 +229,17 @@ void ThreadControllerImpl::DoWork(WorkType work_type) {
DCHECK_GE(any_sequence().do_work_running_count, 0);
LazyNow lazy_now(time_source_);
TimeDelta delay_till_next_task = sequence_->DelayTillNextTask(&lazy_now);
if (delay_till_next_task <= TimeDelta()) {
// The OnSystemIdle callback allows the TimeDomains to advance virtual time
// in which case we now have immediate word to do.
if (delay_till_next_task <= TimeDelta() || sequence_->OnSystemIdle()) {
// The next task needs to run immediately, post a continuation if needed.
if (!any_sequence().immediate_do_work_posted) {
any_sequence().immediate_do_work_posted = true;
task_runner_->PostTask(FROM_HERE, immediate_do_work_closure_);
}
} else if (delay_till_next_task < TimeDelta::Max()) {
return;
}
if (delay_till_next_task < TimeDelta::Max()) {
// The next task needs to run after a delay, post a continuation if
// needed.
TimeTicks next_task_at = lazy_now.Now() + delay_till_next_task;
......@@ -246,10 +250,10 @@ void ThreadControllerImpl::DoWork(WorkType work_type) {
FROM_HERE, cancelable_delayed_do_work_closure_.callback(),
delay_till_next_task);
}
} else {
// There is no next task scheduled.
main_sequence_only().next_delayed_do_work = TimeTicks::Max();
return;
}
// There is no next task scheduled.
main_sequence_only().next_delayed_do_work = TimeTicks::Max();
}
}
......
......@@ -284,9 +284,6 @@ bool ThreadControllerWithMessagePumpImpl::InTopLevelDoWork() const {
}
bool ThreadControllerWithMessagePumpImpl::DoIdleWork() {
// RunLoop::Delegate knows whether we called Run() or RunUntilIdle().
if (ShouldQuitWhenIdle())
Quit();
#if defined(OS_WIN)
bool need_high_res_mode =
main_thread_only().task_source->HasPendingHighResolutionTasks();
......@@ -299,6 +296,14 @@ bool ThreadControllerWithMessagePumpImpl::DoIdleWork() {
Time::ActivateHighResolutionTimer(need_high_res_mode);
}
#endif // defined(OS_WIN)
if (main_thread_only().task_source->OnSystemIdle())
return true; // Pretend we have done work to ensure DoWork is called.
// RunLoop::Delegate knows whether we called Run() or RunUntilIdle().
if (ShouldQuitWhenIdle())
Quit();
return false;
}
......
......@@ -105,6 +105,8 @@ class FakeSequencedTaskSource : public internal::SequencedTaskSource {
bool HasPendingHighResolutionTasks() override { return false; }
bool OnSystemIdle() override { return false; }
private:
TickClock* clock_;
std::queue<PendingTask> tasks_;
......
......@@ -59,6 +59,10 @@ class BASE_EXPORT TimeDomain {
void AsValueInto(trace_event::TracedValue* state) const;
bool HasPendingHighResolutionTasks() const;
// This is the signal that virtual time should step forward. Returns true if
// time advanced and there is now a task to run.
virtual bool MaybeFastForwardToNextTask() = 0;
protected:
TimeDomain();
......
......@@ -49,6 +49,8 @@ class TestTimeDomain : public TimeDomain {
return Optional<TimeDelta>();
}
bool MaybeFastForwardToNextTask() override { return false; }
void AsValueIntoInternal(trace_event::TracedValue* state) const override {}
const char* GetName() const override { return "Test"; }
......
......@@ -54,5 +54,9 @@ base::Optional<base::TimeDelta> ThrottledTimeDomain::DelayTillNextTask(
return base::nullopt;
}
bool ThrottledTimeDomain::MaybeFastForwardToNextTask() {
return false;
}
} // namespace scheduler
} // namespace blink
......@@ -27,6 +27,7 @@ class PLATFORM_EXPORT ThrottledTimeDomain
base::TimeTicks Now() const override;
base::Optional<base::TimeDelta> DelayTillNextTask(
base::sequence_manager::LazyNow* lazy_now) override;
bool MaybeFastForwardToNextTask() override;
protected:
const char* GetName() const override;
......
......@@ -83,15 +83,25 @@ AutoAdvancingVirtualTimeDomain::DelayTillNextTask(
if (run_time <= Now())
return base::TimeDelta();
// Rely on MaybeFastForwardToNextTask to be called to advance
// virtual time.
return base::nullopt;
}
bool AutoAdvancingVirtualTimeDomain::MaybeFastForwardToNextTask() {
if (!can_advance_virtual_time_)
return base::nullopt;
return false;
base::Optional<base::TimeTicks> run_time = NextScheduledRunTime();
if (!run_time)
return false;
if (MaybeAdvanceVirtualTime(*run_time)) {
task_starvation_count_ = 0;
return base::TimeDelta(); // Makes DoWork post an immediate continuation.
return true;
}
return base::nullopt;
return false;
}
void AutoAdvancingVirtualTimeDomain::SetNextDelayedDoWork(
......
......@@ -77,6 +77,7 @@ class PLATFORM_EXPORT AutoAdvancingVirtualTimeDomain
base::TimeTicks Now() const override;
base::Optional<base::TimeDelta> DelayTillNextTask(
base::sequence_manager::LazyNow* lazy_now) override;
bool MaybeFastForwardToNextTask() override;
protected:
const char* GetName() const override;
......
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