• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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