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

Side by Side Diff: base/message_loop/message_loop_task_runner_unittest.cc

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 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/message_loop/message_loop_task_runner.cc ('k') | base/message_loop/message_loop_test.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/message_loop/message_loop_task_runner.h"
6
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/debug/leak_annotations.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_task_runner.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/thread.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/platform_test.h"
18
19 namespace base {
20
21 class MessageLoopTaskRunnerTest : public testing::Test {
22 public:
23 MessageLoopTaskRunnerTest()
24 : current_loop_(new MessageLoop()),
25 task_thread_("task_thread"),
26 thread_sync_(true, false) {}
27
28 void DeleteCurrentMessageLoop() { current_loop_.reset(); }
29
30 protected:
31 void SetUp() override {
32 // Use SetUp() instead of the constructor to avoid posting a task to a
33 // partialy constructed object.
34 task_thread_.Start();
35
36 // Allow us to pause the |task_thread_|'s MessageLoop.
37 task_thread_.message_loop()->PostTask(
38 FROM_HERE, Bind(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper,
39 Unretained(this)));
40 }
41
42 void TearDown() override {
43 // Make sure the |task_thread_| is not blocked, and stop the thread
44 // fully before destuction because its tasks may still depend on the
45 // |thread_sync_| event.
46 thread_sync_.Signal();
47 task_thread_.Stop();
48 DeleteCurrentMessageLoop();
49 }
50
51 // Make LoopRecorder threadsafe so that there is defined behavior even if a
52 // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
53 class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
54 public:
55 LoopRecorder(MessageLoop** run_on,
56 MessageLoop** deleted_on,
57 int* destruct_order)
58 : run_on_(run_on),
59 deleted_on_(deleted_on),
60 destruct_order_(destruct_order) {}
61
62 void RecordRun() { *run_on_ = MessageLoop::current(); }
63
64 private:
65 friend class RefCountedThreadSafe<LoopRecorder>;
66 ~LoopRecorder() {
67 *deleted_on_ = MessageLoop::current();
68 *destruct_order_ = g_order.GetNext();
69 }
70
71 MessageLoop** run_on_;
72 MessageLoop** deleted_on_;
73 int* destruct_order_;
74 };
75
76 static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
77 recorder->RecordRun();
78 }
79
80 static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
81 recorder->RecordRun();
82 MessageLoop::current()->QuitWhenIdle();
83 }
84
85 void UnblockTaskThread() { thread_sync_.Signal(); }
86
87 void BlockTaskThreadHelper() { thread_sync_.Wait(); }
88
89 static StaticAtomicSequenceNumber g_order;
90
91 scoped_ptr<MessageLoop> current_loop_;
92 Thread task_thread_;
93
94 private:
95 base::WaitableEvent thread_sync_;
96 };
97
98 StaticAtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
99
100 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_Basic) {
101 MessageLoop* task_run_on = NULL;
102 MessageLoop* task_deleted_on = NULL;
103 int task_delete_order = -1;
104 MessageLoop* reply_run_on = NULL;
105 MessageLoop* reply_deleted_on = NULL;
106 int reply_delete_order = -1;
107
108 scoped_refptr<LoopRecorder> task_recoder =
109 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
110 scoped_refptr<LoopRecorder> reply_recoder =
111 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
112
113 ASSERT_TRUE(task_thread_.task_runner()->PostTaskAndReply(
114 FROM_HERE, Bind(&RecordLoop, task_recoder),
115 Bind(&RecordLoopAndQuit, reply_recoder)));
116
117 // Die if base::Bind doesn't retain a reference to the recorders.
118 task_recoder = NULL;
119 reply_recoder = NULL;
120 ASSERT_FALSE(task_deleted_on);
121 ASSERT_FALSE(reply_deleted_on);
122
123 UnblockTaskThread();
124 current_loop_->Run();
125
126 EXPECT_EQ(task_thread_.message_loop(), task_run_on);
127 EXPECT_EQ(current_loop_.get(), task_deleted_on);
128 EXPECT_EQ(current_loop_.get(), reply_run_on);
129 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
130 EXPECT_LT(task_delete_order, reply_delete_order);
131 }
132
133 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
134 MessageLoop* task_run_on = NULL;
135 MessageLoop* task_deleted_on = NULL;
136 int task_delete_order = -1;
137 MessageLoop* reply_run_on = NULL;
138 MessageLoop* reply_deleted_on = NULL;
139 int reply_delete_order = -1;
140
141 scoped_refptr<LoopRecorder> task_recoder =
142 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
143 scoped_refptr<LoopRecorder> reply_recoder =
144 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
145
146 // Grab a task runner to a dead MessageLoop.
147 scoped_refptr<SingleThreadTaskRunner> task_runner =
148 task_thread_.task_runner();
149 UnblockTaskThread();
150 task_thread_.Stop();
151
152 ASSERT_FALSE(
153 task_runner->PostTaskAndReply(FROM_HERE, Bind(&RecordLoop, task_recoder),
154 Bind(&RecordLoopAndQuit, reply_recoder)));
155
156 // The relay should have properly deleted its resources leaving us as the only
157 // reference.
158 EXPECT_EQ(task_delete_order, reply_delete_order);
159 ASSERT_TRUE(task_recoder->HasOneRef());
160 ASSERT_TRUE(reply_recoder->HasOneRef());
161
162 // Nothing should have run though.
163 EXPECT_FALSE(task_run_on);
164 EXPECT_FALSE(reply_run_on);
165 }
166
167 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_SameLoop) {
168 MessageLoop* task_run_on = NULL;
169 MessageLoop* task_deleted_on = NULL;
170 int task_delete_order = -1;
171 MessageLoop* reply_run_on = NULL;
172 MessageLoop* reply_deleted_on = NULL;
173 int reply_delete_order = -1;
174
175 scoped_refptr<LoopRecorder> task_recoder =
176 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
177 scoped_refptr<LoopRecorder> reply_recoder =
178 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
179
180 // Enqueue the relay.
181 ASSERT_TRUE(current_loop_->task_runner()->PostTaskAndReply(
182 FROM_HERE, Bind(&RecordLoop, task_recoder),
183 Bind(&RecordLoopAndQuit, reply_recoder)));
184
185 // Die if base::Bind doesn't retain a reference to the recorders.
186 task_recoder = NULL;
187 reply_recoder = NULL;
188 ASSERT_FALSE(task_deleted_on);
189 ASSERT_FALSE(reply_deleted_on);
190
191 current_loop_->Run();
192
193 EXPECT_EQ(current_loop_.get(), task_run_on);
194 EXPECT_EQ(current_loop_.get(), task_deleted_on);
195 EXPECT_EQ(current_loop_.get(), reply_run_on);
196 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
197 EXPECT_LT(task_delete_order, reply_delete_order);
198 }
199
200 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
201 // Annotate the scope as having memory leaks to suppress heapchecker reports.
202 ANNOTATE_SCOPED_MEMORY_LEAK;
203 MessageLoop* task_run_on = NULL;
204 MessageLoop* task_deleted_on = NULL;
205 int task_delete_order = -1;
206 MessageLoop* reply_run_on = NULL;
207 MessageLoop* reply_deleted_on = NULL;
208 int reply_delete_order = -1;
209
210 scoped_refptr<LoopRecorder> task_recoder =
211 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
212 scoped_refptr<LoopRecorder> reply_recoder =
213 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
214
215 // Enqueue the relay.
216 task_thread_.task_runner()->PostTaskAndReply(
217 FROM_HERE, Bind(&RecordLoop, task_recoder),
218 Bind(&RecordLoopAndQuit, reply_recoder));
219
220 // Die if base::Bind doesn't retain a reference to the recorders.
221 task_recoder = NULL;
222 reply_recoder = NULL;
223 ASSERT_FALSE(task_deleted_on);
224 ASSERT_FALSE(reply_deleted_on);
225
226 UnblockTaskThread();
227
228 // Mercilessly whack the current loop before |reply| gets to run.
229 current_loop_.reset();
230
231 // This should ensure the relay has been run. We need to record the
232 // MessageLoop pointer before stopping the thread because Thread::Stop() will
233 // NULL out its own pointer.
234 MessageLoop* task_loop = task_thread_.message_loop();
235 task_thread_.Stop();
236
237 EXPECT_EQ(task_loop, task_run_on);
238 ASSERT_FALSE(task_deleted_on);
239 EXPECT_FALSE(reply_run_on);
240 ASSERT_FALSE(reply_deleted_on);
241 EXPECT_EQ(task_delete_order, reply_delete_order);
242
243 // The PostTaskAndReplyRelay is leaked here. Even if we had a reference to
244 // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
245 // checks that MessageLoop::current() is the the same as when the
246 // PostTaskAndReplyRelay object was constructed. However, this loop must have
247 // aleady been deleted in order to perform this test. See
248 // http://crbug.com/86301.
249 }
250
251 class MessageLoopTaskRunnerThreadingTest : public testing::Test {
252 public:
253 void Release() const {
254 AssertOnIOThread();
255 Quit();
256 }
257
258 void Quit() const {
259 loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
260 }
261
262 void AssertOnIOThread() const {
263 ASSERT_TRUE(io_thread_->task_runner()->BelongsToCurrentThread());
264 ASSERT_EQ(io_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
265 }
266
267 void AssertOnFileThread() const {
268 ASSERT_TRUE(file_thread_->task_runner()->BelongsToCurrentThread());
269 ASSERT_EQ(file_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
270 }
271
272 protected:
273 void SetUp() override {
274 io_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO"));
275 file_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File"));
276 io_thread_->Start();
277 file_thread_->Start();
278 }
279
280 void TearDown() override {
281 io_thread_->Stop();
282 file_thread_->Stop();
283 }
284
285 static void BasicFunction(MessageLoopTaskRunnerThreadingTest* test) {
286 test->AssertOnFileThread();
287 test->Quit();
288 }
289
290 static void AssertNotRun() { FAIL() << "Callback Should not get executed."; }
291
292 class DeletedOnFile {
293 public:
294 explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest* test)
295 : test_(test) {}
296
297 ~DeletedOnFile() {
298 test_->AssertOnFileThread();
299 test_->Quit();
300 }
301
302 private:
303 MessageLoopTaskRunnerThreadingTest* test_;
304 };
305
306 scoped_ptr<Thread> io_thread_;
307 scoped_ptr<Thread> file_thread_;
308
309 private:
310 mutable MessageLoop loop_;
311 };
312
313 TEST_F(MessageLoopTaskRunnerThreadingTest, Release) {
314 EXPECT_TRUE(io_thread_->task_runner()->ReleaseSoon(FROM_HERE, this));
315 MessageLoop::current()->Run();
316 }
317
318 TEST_F(MessageLoopTaskRunnerThreadingTest, Delete) {
319 DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
320 EXPECT_TRUE(
321 file_thread_->task_runner()->DeleteSoon(FROM_HERE, deleted_on_file));
322 MessageLoop::current()->Run();
323 }
324
325 TEST_F(MessageLoopTaskRunnerThreadingTest, PostTask) {
326 EXPECT_TRUE(file_thread_->task_runner()->PostTask(
327 FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::BasicFunction,
328 Unretained(this))));
329 MessageLoop::current()->Run();
330 }
331
332 TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadExits) {
333 scoped_ptr<Thread> test_thread(
334 new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
335 test_thread->Start();
336 scoped_refptr<SingleThreadTaskRunner> task_runner =
337 test_thread->task_runner();
338 test_thread->Stop();
339
340 bool ret = task_runner->PostTask(
341 FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
342 EXPECT_FALSE(ret);
343 }
344
345 TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadIsDeleted) {
346 scoped_refptr<SingleThreadTaskRunner> task_runner;
347 {
348 scoped_ptr<Thread> test_thread(
349 new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
350 test_thread->Start();
351 task_runner = test_thread->task_runner();
352 }
353 bool ret = task_runner->PostTask(
354 FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
355 EXPECT_FALSE(ret);
356 }
357
358 } // namespace base
OLDNEW
« no previous file with comments | « base/message_loop/message_loop_task_runner.cc ('k') | base/message_loop/message_loop_test.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698