Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Side by Side Diff: base/run_loop_unittest.cc

Issue 2892993002: Make RunLoop::Quit() thread-safe. (Closed)
Patch Set: add tests that call Quit(WhenIdle) directly, without the Quit(WhenIdle)Closure Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/run_loop.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/run_loop.h" 5 #include "base/run_loop.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/single_thread_task_runner.h" 11 #include "base/single_thread_task_runner.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/task_scheduler/post_task.h"
14 #include "base/test/scoped_task_environment.h"
13 #include "base/threading/thread_task_runner_handle.h" 15 #include "base/threading/thread_task_runner_handle.h"
14 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h" 17 #include "testing/gtest/include/gtest/gtest.h"
16 18
17 namespace base { 19 namespace base {
18 20
19 namespace { 21 namespace {
20 22
21 void QuitWhenIdleTask(RunLoop* run_loop, int* counter) { 23 void QuitWhenIdleTask(RunLoop* run_loop, int* counter) {
22 run_loop->QuitWhenIdle(); 24 run_loop->QuitWhenIdle();
(...skipping 22 matching lines...) Expand all
45 MessageLoop::ScopedNestableTaskAllower allower(MessageLoop::current()); 47 MessageLoop::ScopedNestableTaskAllower allower(MessageLoop::current());
46 nested_run_loop.Run(); 48 nested_run_loop.Run();
47 49
48 ++(*counter); 50 ++(*counter);
49 } 51 }
50 52
51 class RunLoopTest : public testing::Test { 53 class RunLoopTest : public testing::Test {
52 protected: 54 protected:
53 RunLoopTest() = default; 55 RunLoopTest() = default;
54 56
55 MessageLoop message_loop_; 57 test::ScopedTaskEnvironment task_environment_;
56 RunLoop run_loop_; 58 RunLoop run_loop_;
57 int counter_ = 0; 59 int counter_ = 0;
58 60
59 private: 61 private:
60 DISALLOW_COPY_AND_ASSIGN(RunLoopTest); 62 DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
61 }; 63 };
62 64
63 } // namespace 65 } // namespace
64 66
65 TEST_F(RunLoopTest, QuitWhenIdle) { 67 TEST_F(RunLoopTest, QuitWhenIdle) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 TEST_F(RunLoopTest, QuitWhenIdleClosureAfterRunLoopScope) { 109 TEST_F(RunLoopTest, QuitWhenIdleClosureAfterRunLoopScope) {
108 Closure quit_when_idle_closure; 110 Closure quit_when_idle_closure;
109 { 111 {
110 RunLoop run_loop; 112 RunLoop run_loop;
111 quit_when_idle_closure = run_loop.QuitWhenIdleClosure(); 113 quit_when_idle_closure = run_loop.QuitWhenIdleClosure();
112 run_loop.RunUntilIdle(); 114 run_loop.RunUntilIdle();
113 } 115 }
114 quit_when_idle_closure.Run(); 116 quit_when_idle_closure.Run();
115 } 117 }
116 118
119 // Verify that Quit can be executed from another sequence.
120 TEST_F(RunLoopTest, QuitFromOtherSequence) {
121 scoped_refptr<SequencedTaskRunner> other_sequence =
122 CreateSequencedTaskRunnerWithTraits({});
123
124 // Always expected to run before asynchronous Quit() kicks in.
125 ThreadTaskRunnerHandle::Get()->PostTask(
126 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
127
128 WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL,
129 WaitableEvent::InitialState::NOT_SIGNALED);
130 other_sequence->PostTask(
131 FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); },
132 Unretained(&run_loop_)));
133 other_sequence->PostTask(
134 FROM_HERE,
135 base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit)));
136
137 // Anything that's posted after the Quit closure was posted back to this
138 // sequence shouldn't get a chance to run.
139 loop_was_quit.Wait();
140 ThreadTaskRunnerHandle::Get()->PostTask(
141 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
142
143 run_loop_.Run();
144
145 EXPECT_EQ(1, counter_);
146 }
147
148 // Verify that QuitClosure can be executed from another sequence.
149 TEST_F(RunLoopTest, QuitFromOtherSequenceWithClosure) {
150 scoped_refptr<SequencedTaskRunner> other_sequence =
151 CreateSequencedTaskRunnerWithTraits({});
152
153 // Always expected to run before asynchronous Quit() kicks in.
154 ThreadTaskRunnerHandle::Get()->PostTask(
155 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
156
157 WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL,
158 WaitableEvent::InitialState::NOT_SIGNALED);
159 other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure());
160 other_sequence->PostTask(
161 FROM_HERE,
162 base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit)));
163
164 // Anything that's posted after the Quit closure was posted back to this
165 // sequence shouldn't get a chance to run.
166 loop_was_quit.Wait();
167 ThreadTaskRunnerHandle::Get()->PostTask(
168 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
169
170 run_loop_.Run();
171
172 EXPECT_EQ(1, counter_);
173 }
174
175 // Verify that Quit can be executed from another sequence even when the
176 // Quit is racing with Run() -- i.e. forgo the WaitableEvent used above.
177 TEST_F(RunLoopTest, QuitFromOtherSequenceRacy) {
178 scoped_refptr<SequencedTaskRunner> other_sequence =
179 CreateSequencedTaskRunnerWithTraits({});
180
181 // Always expected to run before asynchronous Quit() kicks in.
182 ThreadTaskRunnerHandle::Get()->PostTask(
183 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
184
185 other_sequence->PostTask(
186 FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); },
187 Unretained(&run_loop_)));
188
189 run_loop_.Run();
190
191 EXPECT_EQ(1, counter_);
192 }
193
194 // Verify that QuitClosure can be executed from another sequence even when the
195 // Quit is racing with Run() -- i.e. forgo the WaitableEvent used above.
196 TEST_F(RunLoopTest, QuitFromOtherSequenceRacyWithClosure) {
197 scoped_refptr<SequencedTaskRunner> other_sequence =
198 CreateSequencedTaskRunnerWithTraits({});
199
200 // Always expected to run before asynchronous Quit() kicks in.
201 ThreadTaskRunnerHandle::Get()->PostTask(
202 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
203
204 other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure());
205
206 run_loop_.Run();
207
208 EXPECT_EQ(1, counter_);
209 }
210
211 // Verify that QuitWhenIdle can be executed from another sequence.
212 TEST_F(RunLoopTest, QuitWhenIdleFromOtherSequence) {
213 scoped_refptr<SequencedTaskRunner> other_sequence =
214 CreateSequencedTaskRunnerWithTraits({});
215
216 ThreadTaskRunnerHandle::Get()->PostTask(
217 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
218
219 other_sequence->PostTask(
220 FROM_HERE,
221 base::BindOnce([](RunLoop* run_loop) { run_loop->QuitWhenIdle(); },
222 Unretained(&run_loop_)));
223
224 ThreadTaskRunnerHandle::Get()->PostTask(
225 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
226
227 run_loop_.Run();
228
229 // Regardless of the outcome of the race this thread shouldn't have been idle
230 // until the counter was ticked twice.
231 EXPECT_EQ(2, counter_);
232 }
233
234 // Verify that QuitWhenIdleClosure can be executed from another sequence.
235 TEST_F(RunLoopTest, QuitWhenIdleFromOtherSequenceWithClosure) {
236 scoped_refptr<SequencedTaskRunner> other_sequence =
237 CreateSequencedTaskRunnerWithTraits({});
238
239 ThreadTaskRunnerHandle::Get()->PostTask(
240 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
241
242 other_sequence->PostTask(FROM_HERE, run_loop_.QuitWhenIdleClosure());
243
244 ThreadTaskRunnerHandle::Get()->PostTask(
245 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
246
247 run_loop_.Run();
248
249 // Regardless of the outcome of the race this thread shouldn't have been idle
250 // until the counter was ticked twice.
251 EXPECT_EQ(2, counter_);
252 }
253
117 TEST_F(RunLoopTest, IsRunningOnCurrentThread) { 254 TEST_F(RunLoopTest, IsRunningOnCurrentThread) {
118 EXPECT_FALSE(RunLoop::IsRunningOnCurrentThread()); 255 EXPECT_FALSE(RunLoop::IsRunningOnCurrentThread());
119 ThreadTaskRunnerHandle::Get()->PostTask( 256 ThreadTaskRunnerHandle::Get()->PostTask(
120 FROM_HERE, 257 FROM_HERE,
121 Bind([]() { EXPECT_TRUE(RunLoop::IsRunningOnCurrentThread()); })); 258 Bind([]() { EXPECT_TRUE(RunLoop::IsRunningOnCurrentThread()); }));
122 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure()); 259 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
123 run_loop_.Run(); 260 run_loop_.Run();
124 } 261 }
125 262
126 TEST_F(RunLoopTest, IsNestedOnCurrentThread) { 263 TEST_F(RunLoopTest, IsNestedOnCurrentThread) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 336
200 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind([]() { 337 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind([]() {
201 RunLoop nested_run_loop; 338 RunLoop nested_run_loop;
202 nested_run_loop.RunUntilIdle(); 339 nested_run_loop.RunUntilIdle();
203 })); 340 }));
204 EXPECT_DEATH({ run_loop_.RunUntilIdle(); }, ""); 341 EXPECT_DEATH({ run_loop_.RunUntilIdle(); }, "");
205 } 342 }
206 #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) 343 #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
207 344
208 } // namespace base 345 } // namespace base
OLDNEW
« no previous file with comments | « base/run_loop.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698