Commit 80bdddf5 authored by Francois Doray's avatar Francois Doray Committed by Commit Bot

Add base::RunLoop::NestingObserver::OnExitNestedRunLoop().

This method is called when a nested loop is done running work.
It will help simplify the TaskQueueManager code.

Use case:
The blink scheduler needs to adjust the time domain
when there is a transition between a nested/non-nested scope.
https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc?l=2302&rcl=614a67e2c14cf8bb9a06f4fe8da7625cbf1ea7d7
Currently, it checks base::RunLoop::IsNestedOnCurrentThread()
every time a task completes to detect transitions between
a nested/non-nested scope. Code would be simpler with
an explicit notification.

Bug: 783309
Change-Id: I9748c287ad8418831598d84f45a518e4138c5e1b
Reviewed-on: https://chromium-review.googlesource.com/766388Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Commit-Queue: François Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#527112}
parent c83ee95a
......@@ -321,6 +321,11 @@ void RunLoop::AfterRun() {
RunLoop* previous_run_loop =
active_run_loops_.empty() ? nullptr : active_run_loops_.top();
if (previous_run_loop) {
for (auto& observer : delegate_->nesting_observers_)
observer.OnExitNestedRunLoop();
}
// Execute deferred Quit, if any:
if (previous_run_loop && previous_run_loop->quit_called_)
delegate_->Quit();
......
......@@ -130,12 +130,13 @@ class BASE_EXPORT RunLoop {
// Safe to call before RegisterDelegateForCurrentThread().
static bool IsNestedOnCurrentThread();
// A NestingObserver is notified when a nested RunLoop begins. The observers
// are notified before the current thread's RunLoop::Delegate::Run() is
// invoked and nested work begins.
// A NestingObserver is notified when a nested RunLoop begins and ends.
class BASE_EXPORT NestingObserver {
public:
// Notified before a nested loop starts running work on the current thread.
virtual void OnBeginNestedRunLoop() = 0;
// Notified after a nested loop is done running work on the current thread.
virtual void OnExitNestedRunLoop() {}
protected:
virtual ~NestingObserver() = default;
......
......@@ -570,21 +570,37 @@ TEST_P(RunLoopTest, IsNestedOnCurrentThread) {
run_loop_.Run();
}
namespace {
class MockNestingObserver : public RunLoop::NestingObserver {
public:
MockNestingObserver() = default;
// RunLoop::NestingObserver:
MOCK_METHOD0(OnBeginNestedRunLoop, void());
MOCK_METHOD0(OnExitNestedRunLoop, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockNestingObserver);
};
class MockTask {
public:
MockTask() = default;
MOCK_METHOD0(Task, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockTask);
};
} // namespace
TEST_P(RunLoopTest, NestingObservers) {
EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
testing::StrictMock<MockNestingObserver> nesting_observer;
testing::StrictMock<MockTask> mock_task_a;
testing::StrictMock<MockTask> mock_task_b;
RunLoop::AddNestingObserverOnCurrentThread(&nesting_observer);
......@@ -599,14 +615,27 @@ TEST_P(RunLoopTest, NestingObservers) {
nested_run_loop.Run();
});
// Generate a stack of nested RunLoops, an OnBeginNestedRunLoop() is
// expected when beginning each nesting depth.
// Generate a stack of nested RunLoops. OnBeginNestedRunLoop() is expected
// when beginning each nesting depth and OnExitNestedRunLoop() is expected
// when exiting each nesting depth.
ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&MockTask::Task, base::Unretained(&mock_task_a)));
ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&MockTask::Task, base::Unretained(&mock_task_b)));
EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop()).Times(2);
run_loop_.Run();
{
testing::InSequence in_sequence;
EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop());
EXPECT_CALL(mock_task_a, Task());
EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop());
EXPECT_CALL(mock_task_b, Task());
EXPECT_CALL(nesting_observer, OnExitNestedRunLoop()).Times(2);
}
run_loop_.RunUntilIdle();
RunLoop::RemoveNestingObserverOnCurrentThread(&nesting_observer);
}
......
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