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.
5 #include "base/message_loop/message_loop_task_runner.h"
7 #include "base/atomic_sequence_num.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"
21 class MessageLoopTaskRunnerTest
: public testing::Test
{
23 MessageLoopTaskRunnerTest()
24 : current_loop_(new MessageLoop()),
25 task_thread_("task_thread"),
26 thread_sync_(true, false) {}
28 void DeleteCurrentMessageLoop() { current_loop_
.reset(); }
31 void SetUp() override
{
32 // Use SetUp() instead of the constructor to avoid posting a task to a
33 // partially constructed object.
36 // Allow us to pause the |task_thread_|'s MessageLoop.
37 task_thread_
.message_loop()->PostTask(
38 FROM_HERE
, Bind(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper
,
42 void TearDown() override
{
43 // Make sure the |task_thread_| is not blocked, and stop the thread
44 // fully before destruction because its tasks may still depend on the
45 // |thread_sync_| event.
46 thread_sync_
.Signal();
48 DeleteCurrentMessageLoop();
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
> {
55 LoopRecorder(MessageLoop
** run_on
,
56 MessageLoop
** deleted_on
,
59 deleted_on_(deleted_on
),
60 destruct_order_(destruct_order
) {}
62 void RecordRun() { *run_on_
= MessageLoop::current(); }
65 friend class RefCountedThreadSafe
<LoopRecorder
>;
67 *deleted_on_
= MessageLoop::current();
68 *destruct_order_
= g_order
.GetNext();
71 MessageLoop
** run_on_
;
72 MessageLoop
** deleted_on_
;
76 static void RecordLoop(scoped_refptr
<LoopRecorder
> recorder
) {
77 recorder
->RecordRun();
80 static void RecordLoopAndQuit(scoped_refptr
<LoopRecorder
> recorder
) {
81 recorder
->RecordRun();
82 MessageLoop::current()->QuitWhenIdle();
85 void UnblockTaskThread() { thread_sync_
.Signal(); }
87 void BlockTaskThreadHelper() { thread_sync_
.Wait(); }
89 static StaticAtomicSequenceNumber g_order
;
91 scoped_ptr
<MessageLoop
> current_loop_
;
95 base::WaitableEvent thread_sync_
;
98 StaticAtomicSequenceNumber
MessageLoopTaskRunnerTest::g_order
;
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;
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
);
113 ASSERT_TRUE(task_thread_
.task_runner()->PostTaskAndReply(
114 FROM_HERE
, Bind(&RecordLoop
, task_recoder
),
115 Bind(&RecordLoopAndQuit
, reply_recoder
)));
117 // Die if base::Bind doesn't retain a reference to the recorders.
119 reply_recoder
= NULL
;
120 ASSERT_FALSE(task_deleted_on
);
121 ASSERT_FALSE(reply_deleted_on
);
124 current_loop_
->Run();
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
);
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;
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
);
146 // Grab a task runner to a dead MessageLoop.
147 scoped_refptr
<SingleThreadTaskRunner
> task_runner
=
148 task_thread_
.task_runner();
153 task_runner
->PostTaskAndReply(FROM_HERE
, Bind(&RecordLoop
, task_recoder
),
154 Bind(&RecordLoopAndQuit
, reply_recoder
)));
156 // The relay should have properly deleted its resources leaving us as the only
158 EXPECT_EQ(task_delete_order
, reply_delete_order
);
159 ASSERT_TRUE(task_recoder
->HasOneRef());
160 ASSERT_TRUE(reply_recoder
->HasOneRef());
162 // Nothing should have run though.
163 EXPECT_FALSE(task_run_on
);
164 EXPECT_FALSE(reply_run_on
);
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;
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
);
180 // Enqueue the relay.
181 ASSERT_TRUE(current_loop_
->task_runner()->PostTaskAndReply(
182 FROM_HERE
, Bind(&RecordLoop
, task_recoder
),
183 Bind(&RecordLoopAndQuit
, reply_recoder
)));
185 // Die if base::Bind doesn't retain a reference to the recorders.
187 reply_recoder
= NULL
;
188 ASSERT_FALSE(task_deleted_on
);
189 ASSERT_FALSE(reply_deleted_on
);
191 current_loop_
->Run();
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
);
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;
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
);
215 // Enqueue the relay.
216 task_thread_
.task_runner()->PostTaskAndReply(
217 FROM_HERE
, Bind(&RecordLoop
, task_recoder
),
218 Bind(&RecordLoopAndQuit
, reply_recoder
));
220 // Die if base::Bind doesn't retain a reference to the recorders.
222 reply_recoder
= NULL
;
223 ASSERT_FALSE(task_deleted_on
);
224 ASSERT_FALSE(reply_deleted_on
);
228 // Mercilessly whack the current loop before |reply| gets to run.
229 current_loop_
.reset();
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();
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
);
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 // already been deleted in order to perform this test. See
248 // http://crbug.com/86301.
251 class MessageLoopTaskRunnerThreadingTest
: public testing::Test
{
253 void Release() const {
259 loop_
.PostTask(FROM_HERE
, MessageLoop::QuitWhenIdleClosure());
262 void AssertOnIOThread() const {
263 ASSERT_TRUE(io_thread_
->task_runner()->BelongsToCurrentThread());
264 ASSERT_EQ(io_thread_
->task_runner(), ThreadTaskRunnerHandle::Get());
267 void AssertOnFileThread() const {
268 ASSERT_TRUE(file_thread_
->task_runner()->BelongsToCurrentThread());
269 ASSERT_EQ(file_thread_
->task_runner(), ThreadTaskRunnerHandle::Get());
273 void SetUp() override
{
274 io_thread_
.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO"));
275 file_thread_
.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File"));
277 file_thread_
->Start();
280 void TearDown() override
{
282 file_thread_
->Stop();
285 static void BasicFunction(MessageLoopTaskRunnerThreadingTest
* test
) {
286 test
->AssertOnFileThread();
290 static void AssertNotRun() { FAIL() << "Callback Should not get executed."; }
292 class DeletedOnFile
{
294 explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest
* test
)
298 test_
->AssertOnFileThread();
303 MessageLoopTaskRunnerThreadingTest
* test_
;
306 scoped_ptr
<Thread
> io_thread_
;
307 scoped_ptr
<Thread
> file_thread_
;
310 mutable MessageLoop loop_
;
313 TEST_F(MessageLoopTaskRunnerThreadingTest
, Release
) {
314 EXPECT_TRUE(io_thread_
->task_runner()->ReleaseSoon(FROM_HERE
, this));
315 MessageLoop::current()->Run();
318 TEST_F(MessageLoopTaskRunnerThreadingTest
, Delete
) {
319 DeletedOnFile
* deleted_on_file
= new DeletedOnFile(this);
321 file_thread_
->task_runner()->DeleteSoon(FROM_HERE
, deleted_on_file
));
322 MessageLoop::current()->Run();
325 TEST_F(MessageLoopTaskRunnerThreadingTest
, PostTask
) {
326 EXPECT_TRUE(file_thread_
->task_runner()->PostTask(
327 FROM_HERE
, Bind(&MessageLoopTaskRunnerThreadingTest::BasicFunction
,
329 MessageLoop::current()->Run();
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();
340 bool ret
= task_runner
->PostTask(
341 FROM_HERE
, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun
));
345 TEST_F(MessageLoopTaskRunnerThreadingTest
, PostTaskAfterThreadIsDeleted
) {
346 scoped_refptr
<SingleThreadTaskRunner
> task_runner
;
348 scoped_ptr
<Thread
> test_thread(
349 new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
350 test_thread
->Start();
351 task_runner
= test_thread
->task_runner();
353 bool ret
= task_runner
->PostTask(
354 FROM_HERE
, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun
));