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