Index: base/run_loop_unittest.cc |
diff --git a/base/run_loop_unittest.cc b/base/run_loop_unittest.cc |
index ea596c60fb76f89946967e985fb690627937c2ef..947e3b920f2e9a30f1e8a23f26f6570605d0dfac 100644 |
--- a/base/run_loop_unittest.cc |
+++ b/base/run_loop_unittest.cc |
@@ -8,8 +8,10 @@ |
#include "base/bind_helpers.h" |
#include "base/location.h" |
#include "base/macros.h" |
-#include "base/message_loop/message_loop.h" |
#include "base/single_thread_task_runner.h" |
+#include "base/synchronization/waitable_event.h" |
+#include "base/task_scheduler/post_task.h" |
+#include "base/test/scoped_task_environment.h" |
#include "base/threading/thread_task_runner_handle.h" |
#include "testing/gmock/include/gmock/gmock.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -52,7 +54,7 @@ class RunLoopTest : public testing::Test { |
protected: |
RunLoopTest() = default; |
- MessageLoop message_loop_; |
+ test::ScopedTaskEnvironment task_environment_; |
RunLoop run_loop_; |
int counter_ = 0; |
@@ -114,6 +116,141 @@ TEST_F(RunLoopTest, QuitWhenIdleClosureAfterRunLoopScope) { |
quit_when_idle_closure.Run(); |
} |
+// Verify that Quit can be executed from another sequence. |
+TEST_F(RunLoopTest, QuitFromOtherSequence) { |
+ scoped_refptr<SequencedTaskRunner> other_sequence = |
+ CreateSequencedTaskRunnerWithTraits({}); |
+ |
+ // Always expected to run before asynchronous Quit() kicks in. |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL, |
+ WaitableEvent::InitialState::NOT_SIGNALED); |
+ other_sequence->PostTask( |
+ FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); }, |
+ Unretained(&run_loop_))); |
+ other_sequence->PostTask( |
+ FROM_HERE, |
+ base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit))); |
+ |
+ // Anything that's posted after the Quit closure was posted back to this |
+ // sequence shouldn't get a chance to run. |
+ loop_was_quit.Wait(); |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ run_loop_.Run(); |
+ |
+ EXPECT_EQ(1, counter_); |
+} |
+ |
+// Verify that QuitClosure can be executed from another sequence. |
+TEST_F(RunLoopTest, QuitFromOtherSequenceWithClosure) { |
+ scoped_refptr<SequencedTaskRunner> other_sequence = |
+ CreateSequencedTaskRunnerWithTraits({}); |
+ |
+ // Always expected to run before asynchronous Quit() kicks in. |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL, |
+ WaitableEvent::InitialState::NOT_SIGNALED); |
+ other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure()); |
+ other_sequence->PostTask( |
+ FROM_HERE, |
+ base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit))); |
+ |
+ // Anything that's posted after the Quit closure was posted back to this |
+ // sequence shouldn't get a chance to run. |
+ loop_was_quit.Wait(); |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ run_loop_.Run(); |
+ |
+ EXPECT_EQ(1, counter_); |
+} |
+ |
+// Verify that Quit can be executed from another sequence even when the |
+// Quit is racing with Run() -- i.e. forgo the WaitableEvent used above. |
+TEST_F(RunLoopTest, QuitFromOtherSequenceRacy) { |
+ scoped_refptr<SequencedTaskRunner> other_sequence = |
+ CreateSequencedTaskRunnerWithTraits({}); |
+ |
+ // Always expected to run before asynchronous Quit() kicks in. |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ other_sequence->PostTask( |
+ FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); }, |
+ Unretained(&run_loop_))); |
+ |
+ run_loop_.Run(); |
+ |
+ EXPECT_EQ(1, counter_); |
+} |
+ |
+// Verify that QuitClosure can be executed from another sequence even when the |
+// Quit is racing with Run() -- i.e. forgo the WaitableEvent used above. |
+TEST_F(RunLoopTest, QuitFromOtherSequenceRacyWithClosure) { |
+ scoped_refptr<SequencedTaskRunner> other_sequence = |
+ CreateSequencedTaskRunnerWithTraits({}); |
+ |
+ // Always expected to run before asynchronous Quit() kicks in. |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure()); |
+ |
+ run_loop_.Run(); |
+ |
+ EXPECT_EQ(1, counter_); |
+} |
+ |
+// Verify that QuitWhenIdle can be executed from another sequence. |
+TEST_F(RunLoopTest, QuitWhenIdleFromOtherSequence) { |
+ scoped_refptr<SequencedTaskRunner> other_sequence = |
+ CreateSequencedTaskRunnerWithTraits({}); |
+ |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ other_sequence->PostTask( |
+ FROM_HERE, |
+ base::BindOnce([](RunLoop* run_loop) { run_loop->QuitWhenIdle(); }, |
+ Unretained(&run_loop_))); |
+ |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ run_loop_.Run(); |
+ |
+ // Regardless of the outcome of the race this thread shouldn't have been idle |
+ // until the counter was ticked twice. |
+ EXPECT_EQ(2, counter_); |
+} |
+ |
+// Verify that QuitWhenIdleClosure can be executed from another sequence. |
+TEST_F(RunLoopTest, QuitWhenIdleFromOtherSequenceWithClosure) { |
+ scoped_refptr<SequencedTaskRunner> other_sequence = |
+ CreateSequencedTaskRunnerWithTraits({}); |
+ |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ other_sequence->PostTask(FROM_HERE, run_loop_.QuitWhenIdleClosure()); |
+ |
+ ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_))); |
+ |
+ run_loop_.Run(); |
+ |
+ // Regardless of the outcome of the race this thread shouldn't have been idle |
+ // until the counter was ticked twice. |
+ EXPECT_EQ(2, counter_); |
+} |
+ |
TEST_F(RunLoopTest, IsRunningOnCurrentThread) { |
EXPECT_FALSE(RunLoop::IsRunningOnCurrentThread()); |
ThreadTaskRunnerHandle::Get()->PostTask( |