Commit 49c8774b authored by Alex Clarke's avatar Alex Clarke Committed by Commit Bot

[Reland] Use the SequenceManager in ScopedTaskEnvironment

A reland of https://crrev.com/c/1324391

This is necessary because we want content::TestBrowserThreadBundle to
own a BrowserUIThreadScheduler, but that also owns a ScopedTaskEnvironment
and you can't have two SequenceManagers on the same thread.

This patch allows ScopedTaskEnvironment to optionally work with an
externally owned SequenceManager solving the problem.

This implements https://docs.google.com/document/d/1y08C6JQ9Yta3EQXzwIqqIIKHq9500WV6CWFZzZfDx7I/edit?usp=drivesdk,

We now have the ability to mock time on the UI thread.

TBR=asvitkine@chromium.org,miu@chromium.org,gab@chromium.org,fdoray@chromium.org

Bug: 863341, 891670, 708584
Change-Id: Ia4409b885deb9935e6e5b6d99f4598f164d350db
Reviewed-on: https://chromium-review.googlesource.com/c/1354919Reviewed-by: default avatarAlex Clarke <alexclarke@chromium.org>
Commit-Queue: Alex Clarke <alexclarke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612122}
parent c1512330
...@@ -181,6 +181,7 @@ void MessagePumpCFRunLoopBase::Run(Delegate* delegate) { ...@@ -181,6 +181,7 @@ void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
Delegate* last_delegate = delegate_; Delegate* last_delegate = delegate_;
SetDelegate(delegate); SetDelegate(delegate);
ScheduleWork();
DoRun(delegate); DoRun(delegate);
// Restore the previous state of the object. // Restore the previous state of the object.
......
...@@ -268,7 +268,7 @@ bool ThreadControllerWithMessagePumpImpl::DoWorkImpl( ...@@ -268,7 +268,7 @@ bool ThreadControllerWithMessagePumpImpl::DoWorkImpl(
DCHECK_GE(do_work_delay, TimeDelta()); DCHECK_GE(do_work_delay, TimeDelta());
// Schedule a continuation. // Schedule a continuation.
// TODO(altimin, gab): Make this more efficient by merging DoWork // TODO(altimin, gab): Make this more efficient by merging DoWork
// and DoDelayedWork and allowing returing base::TimeTicks() when we have // and DoDelayedWork and allowing returning base::TimeTicks() when we have
// immediate work. // immediate work.
if (do_work_delay.is_zero()) { if (do_work_delay.is_zero()) {
// Need to run new work immediately, but due to the contract of DoWork we // Need to run new work immediately, but due to the contract of DoWork we
...@@ -310,8 +310,12 @@ bool ThreadControllerWithMessagePumpImpl::DoIdleWork() { ...@@ -310,8 +310,12 @@ bool ThreadControllerWithMessagePumpImpl::DoIdleWork() {
} }
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
if (main_thread_only().task_source->OnSystemIdle()) if (main_thread_only().task_source->OnSystemIdle()) {
return true; // Pretend we have done work to ensure DoWork is called. // The OnSystemIdle() callback resulted in more immediate work, so schedule
// a DoWork callback.
pump_->ScheduleWork();
return false;
}
// RunLoop::Delegate knows whether we called Run() or RunUntilIdle(). // RunLoop::Delegate knows whether we called Run() or RunUntilIdle().
if (ShouldQuitWhenIdle()) if (ShouldQuitWhenIdle())
......
This diff is collapsed.
...@@ -9,19 +9,14 @@ ...@@ -9,19 +9,14 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/task/lazy_task_runner.h" #include "base/task/lazy_task_runner.h"
#include "base/task/sequence_manager/sequence_manager.h"
#include "build/build_config.h" #include "build/build_config.h"
namespace base { namespace base {
namespace internal {
class ScopedSetSequenceLocalStorageMapForCurrentThread;
class SequenceLocalStorageMap;
} // namespace internal
class FileDescriptorWatcher; class FileDescriptorWatcher;
class MessageLoop;
class TaskScheduler; class TaskScheduler;
class TestMockTimeTaskRunner;
class TickClock; class TickClock;
namespace test { namespace test {
...@@ -76,6 +71,11 @@ class ScopedTaskEnvironment { ...@@ -76,6 +71,11 @@ class ScopedTaskEnvironment {
MOCK_TIME, MOCK_TIME,
// The main thread pumps UI messages. // The main thread pumps UI messages.
UI, UI,
// The main thread pumps UI messages and uses a mock clock for delayed tasks
// (controllable via FastForward*() methods).
// TODO(gab@): Enable mock time on all threads and make MOCK_TIME
// configurable independent of MainThreadType.
UI_MOCK_TIME,
// The main thread pumps asynchronous IO messages and supports the // The main thread pumps asynchronous IO messages and supports the
// FileDescriptorWatcher API on POSIX. // FileDescriptorWatcher API on POSIX.
IO, IO,
...@@ -94,6 +94,13 @@ class ScopedTaskEnvironment { ...@@ -94,6 +94,13 @@ class ScopedTaskEnvironment {
MainThreadType main_thread_type = MainThreadType::DEFAULT, MainThreadType main_thread_type = MainThreadType::DEFAULT,
ExecutionMode execution_control_mode = ExecutionMode::ASYNC); ExecutionMode execution_control_mode = ExecutionMode::ASYNC);
// Constructs a ScopedTaskEnvironment using a preexisting |sequence_manager|.
// |sequence_manager| must outlive this ScopedTaskEnvironment.
ScopedTaskEnvironment(
sequence_manager::SequenceManager* sequence_manager,
MainThreadType main_thread_type = MainThreadType::DEFAULT,
ExecutionMode execution_control_mode = ExecutionMode::ASYNC);
// Waits until no undelayed TaskScheduler tasks remain. Then, unregisters the // Waits until no undelayed TaskScheduler tasks remain. Then, unregisters the
// TaskScheduler and the (Thread|Sequenced)TaskRunnerHandle. // TaskScheduler and the (Thread|Sequenced)TaskRunnerHandle.
~ScopedTaskEnvironment(); ~ScopedTaskEnvironment();
...@@ -155,24 +162,25 @@ class ScopedTaskEnvironment { ...@@ -155,24 +162,25 @@ class ScopedTaskEnvironment {
TimeDelta NextMainThreadPendingTaskDelay() const; TimeDelta NextMainThreadPendingTaskDelay() const;
private: private:
class MockTimeDomain;
class TestTaskTracker; class TestTaskTracker;
ScopedTaskEnvironment(
std::unique_ptr<sequence_manager::SequenceManager> owned_sequence_manager,
sequence_manager::SequenceManager* sequence_manager,
MainThreadType main_thread_type,
ExecutionMode execution_control_mode);
scoped_refptr<sequence_manager::TaskQueue> CreateDefaultTaskQueue();
const ExecutionMode execution_control_mode_; const ExecutionMode execution_control_mode_;
// Exactly one of these will be non-null to provide the task environment on const std::unique_ptr<MockTimeDomain> mock_time_domain_;
// the main thread. Users of this class should NOT rely on the presence of a const std::unique_ptr<sequence_manager::SequenceManager>
// MessageLoop beyond (Thread|Sequenced)TaskRunnerHandle and RunLoop as owned_sequence_manager_;
// the backing implementation of each MainThreadType may change over time. sequence_manager::SequenceManager* const sequence_manager_;
const std::unique_ptr<MessageLoop> message_loop_;
const scoped_refptr<TestMockTimeTaskRunner> mock_time_task_runner_; scoped_refptr<sequence_manager::TaskQueue> task_queue_;
// Non-null in MOCK_TIME, where an explicit SequenceLocalStorageMap needs to
// be provided. TODO(gab): This can be removed once mock time support is added
// to MessageLoop directly.
const std::unique_ptr<internal::SequenceLocalStorageMap> slsm_for_mock_time_;
const std::unique_ptr<
internal::ScopedSetSequenceLocalStorageMapForCurrentThread>
slsm_registration_for_mock_time_;
#if defined(OS_POSIX) || defined(OS_FUCHSIA) #if defined(OS_POSIX) || defined(OS_FUCHSIA)
// Enables the FileDescriptorWatcher API iff running a MainThreadType::IO. // Enables the FileDescriptorWatcher API iff running a MainThreadType::IO.
......
...@@ -358,6 +358,10 @@ INSTANTIATE_TEST_CASE_P( ...@@ -358,6 +358,10 @@ INSTANTIATE_TEST_CASE_P(
MainThreadMockTime, MainThreadMockTime,
ScopedTaskEnvironmentTest, ScopedTaskEnvironmentTest,
::testing::Values(ScopedTaskEnvironment::MainThreadType::MOCK_TIME)); ::testing::Values(ScopedTaskEnvironment::MainThreadType::MOCK_TIME));
INSTANTIATE_TEST_CASE_P(
MainThreadUiMockTime,
ScopedTaskEnvironmentTest,
::testing::Values(ScopedTaskEnvironment::MainThreadType::UI_MOCK_TIME));
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
MainThreadUI, MainThreadUI,
ScopedTaskEnvironmentTest, ScopedTaskEnvironmentTest,
...@@ -573,6 +577,10 @@ INSTANTIATE_TEST_CASE_P( ...@@ -573,6 +577,10 @@ INSTANTIATE_TEST_CASE_P(
MainThreadMockTime, MainThreadMockTime,
ScopedTaskEnvironmentMockedTime, ScopedTaskEnvironmentMockedTime,
::testing::Values(ScopedTaskEnvironment::MainThreadType::MOCK_TIME)); ::testing::Values(ScopedTaskEnvironment::MainThreadType::MOCK_TIME));
INSTANTIATE_TEST_CASE_P(
MainThreadUiMockTime,
ScopedTaskEnvironmentMockedTime,
::testing::Values(ScopedTaskEnvironment::MainThreadType::UI_MOCK_TIME));
} // namespace test } // namespace test
} // namespace base } // namespace base
...@@ -1304,7 +1304,7 @@ TEST_F(RenderWidgetHostViewMacTest, TimerBasedPhaseInfo) { ...@@ -1304,7 +1304,7 @@ TEST_F(RenderWidgetHostViewMacTest, TimerBasedPhaseInfo) {
// event gets dispatched. // event gets dispatched.
base::RunLoop run_loop; base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), FROM_HERE, run_loop.QuitWhenIdleClosure(),
base::TimeDelta::FromMilliseconds(100)); base::TimeDelta::FromMilliseconds(100));
run_loop.Run(); run_loop.Run();
......
...@@ -1114,6 +1114,9 @@ TEST_P(WebMediaPlayerMSTest, RotationChange) { ...@@ -1114,6 +1114,9 @@ TEST_P(WebMediaPlayerMSTest, RotationChange) {
CheckSizeChanged(gfx::Size(kStandardWidth, kStandardHeight))); CheckSizeChanged(gfx::Size(kStandardWidth, kStandardHeight)));
message_loop_controller_.RunAndWaitForStatus( message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK); media::PipelineStatus::PIPELINE_OK);
// The exact ordering of delayed vs non-delayed tasks is not defined.
// Make sure we run all non-delayed tasks before testing state.
base::RunLoop().RunUntilIdle();
blink::WebSize natural_size = player_->NaturalSize(); blink::WebSize natural_size = player_->NaturalSize();
// Check that height and width are flipped. // Check that height and width are flipped.
EXPECT_EQ(kStandardHeight, natural_size.width); EXPECT_EQ(kStandardHeight, natural_size.width);
...@@ -1132,6 +1135,7 @@ TEST_P(WebMediaPlayerMSTest, RotationChange) { ...@@ -1132,6 +1135,7 @@ TEST_P(WebMediaPlayerMSTest, RotationChange) {
} }
message_loop_controller_.RunAndWaitForStatus( message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK); media::PipelineStatus::PIPELINE_OK);
base::RunLoop().RunUntilIdle();
natural_size = player_->NaturalSize(); natural_size = player_->NaturalSize();
EXPECT_EQ(kStandardHeight, natural_size.height); EXPECT_EQ(kStandardHeight, natural_size.height);
EXPECT_EQ(kStandardWidth, natural_size.width); EXPECT_EQ(kStandardWidth, natural_size.width);
...@@ -1172,6 +1176,9 @@ TEST_P(WebMediaPlayerMSTest, OpacityChange) { ...@@ -1172,6 +1176,9 @@ TEST_P(WebMediaPlayerMSTest, OpacityChange) {
CheckSizeChanged(gfx::Size(kStandardWidth, kStandardHeight))); CheckSizeChanged(gfx::Size(kStandardWidth, kStandardHeight)));
message_loop_controller_.RunAndWaitForStatus( message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK); media::PipelineStatus::PIPELINE_OK);
// The exact ordering of delayed vs non-delayed tasks is not defined.
// Make sure we run all non-delayed tasks before testing state.
base::RunLoop().RunUntilIdle();
if (!enable_surface_layer_for_video_) { if (!enable_surface_layer_for_video_) {
ASSERT_TRUE(layer_ != nullptr); ASSERT_TRUE(layer_ != nullptr);
EXPECT_TRUE(layer_->contents_opaque()); EXPECT_TRUE(layer_->contents_opaque());
...@@ -1187,6 +1194,7 @@ TEST_P(WebMediaPlayerMSTest, OpacityChange) { ...@@ -1187,6 +1194,7 @@ TEST_P(WebMediaPlayerMSTest, OpacityChange) {
} }
message_loop_controller_.RunAndWaitForStatus( message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK); media::PipelineStatus::PIPELINE_OK);
base::RunLoop().RunUntilIdle();
if (!enable_surface_layer_for_video_) { if (!enable_surface_layer_for_video_) {
EXPECT_FALSE(layer_->contents_opaque()); EXPECT_FALSE(layer_->contents_opaque());
} }
...@@ -1201,6 +1209,7 @@ TEST_P(WebMediaPlayerMSTest, OpacityChange) { ...@@ -1201,6 +1209,7 @@ TEST_P(WebMediaPlayerMSTest, OpacityChange) {
} }
message_loop_controller_.RunAndWaitForStatus( message_loop_controller_.RunAndWaitForStatus(
media::PipelineStatus::PIPELINE_OK); media::PipelineStatus::PIPELINE_OK);
base::RunLoop().RunUntilIdle();
if (!enable_surface_layer_for_video_) if (!enable_surface_layer_for_video_)
EXPECT_TRUE(layer_->contents_opaque()); EXPECT_TRUE(layer_->contents_opaque());
......
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