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