• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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_test.h"
6 
7 #include <stddef.h>
8 
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/macros.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/run_loop.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/threading/thread.h"
17 
18 namespace base {
19 namespace test {
20 
21 namespace {
22 
23 class Foo : public RefCounted<Foo> {
24  public:
Foo()25   Foo() : test_count_(0) {
26   }
27 
Test0()28   void Test0() {
29     ++test_count_;
30   }
31 
Test1ConstRef(const std::string & a)32   void Test1ConstRef(const std::string& a) {
33     ++test_count_;
34     result_.append(a);
35   }
36 
Test1Ptr(std::string * a)37   void Test1Ptr(std::string* a) {
38     ++test_count_;
39     result_.append(*a);
40   }
41 
Test1Int(int a)42   void Test1Int(int a) {
43     test_count_ += a;
44   }
45 
Test2Ptr(std::string * a,std::string * b)46   void Test2Ptr(std::string* a, std::string* b) {
47     ++test_count_;
48     result_.append(*a);
49     result_.append(*b);
50   }
51 
Test2Mixed(const std::string & a,std::string * b)52   void Test2Mixed(const std::string& a, std::string* b) {
53     ++test_count_;
54     result_.append(a);
55     result_.append(*b);
56   }
57 
test_count() const58   int test_count() const { return test_count_; }
result() const59   const std::string& result() const { return result_; }
60 
61  private:
62   friend class RefCounted<Foo>;
63 
~Foo()64   ~Foo() {}
65 
66   int test_count_;
67   std::string result_;
68 
69   DISALLOW_COPY_AND_ASSIGN(Foo);
70 };
71 
72 // This function runs slowly to simulate a large amount of work being done.
SlowFunc(TimeDelta pause,int * quit_counter)73 void SlowFunc(TimeDelta pause, int* quit_counter) {
74     PlatformThread::Sleep(pause);
75     if (--(*quit_counter) == 0)
76       MessageLoop::current()->QuitWhenIdle();
77 }
78 
79 // This function records the time when Run was called in a Time object, which is
80 // useful for building a variety of MessageLoop tests.
81 // TODO(sky): remove?
RecordRunTimeFunc(Time * run_time,int * quit_counter)82 void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
83   *run_time = Time::Now();
84 
85     // Cause our Run function to take some time to execute.  As a result we can
86     // count on subsequent RecordRunTimeFunc()s running at a future time,
87     // without worry about the resolution of our system clock being an issue.
88   SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter);
89 }
90 
91 }  // namespace
92 
RunTest_PostTask(MessagePumpFactory factory)93 void RunTest_PostTask(MessagePumpFactory factory) {
94   scoped_ptr<MessagePump> pump(factory());
95   MessageLoop loop(std::move(pump));
96   // Add tests to message loop
97   scoped_refptr<Foo> foo(new Foo());
98   std::string a("a"), b("b"), c("c"), d("d");
99   MessageLoop::current()->PostTask(FROM_HERE, Bind(
100       &Foo::Test0, foo.get()));
101   MessageLoop::current()->PostTask(FROM_HERE, Bind(
102     &Foo::Test1ConstRef, foo.get(), a));
103   MessageLoop::current()->PostTask(FROM_HERE, Bind(
104       &Foo::Test1Ptr, foo.get(), &b));
105   MessageLoop::current()->PostTask(FROM_HERE, Bind(
106       &Foo::Test1Int, foo.get(), 100));
107   MessageLoop::current()->PostTask(FROM_HERE, Bind(
108       &Foo::Test2Ptr, foo.get(), &a, &c));
109   MessageLoop::current()->PostTask(FROM_HERE, Bind(
110       &Foo::Test2Mixed, foo.get(), a, &d));
111   // After all tests, post a message that will shut down the message loop
112   MessageLoop::current()->PostTask(
113       FROM_HERE,
114       Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
115 
116   // Now kick things off
117   MessageLoop::current()->Run();
118 
119   EXPECT_EQ(foo->test_count(), 105);
120   EXPECT_EQ(foo->result(), "abacad");
121 }
122 
RunTest_PostDelayedTask_Basic(MessagePumpFactory factory)123 void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
124   scoped_ptr<MessagePump> pump(factory());
125   MessageLoop loop(std::move(pump));
126 
127   // Test that PostDelayedTask results in a delayed task.
128 
129   const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
130 
131   int num_tasks = 1;
132   Time run_time;
133 
134   loop.PostDelayedTask(
135       FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
136       kDelay);
137 
138   Time time_before_run = Time::Now();
139   loop.Run();
140   Time time_after_run = Time::Now();
141 
142   EXPECT_EQ(0, num_tasks);
143   EXPECT_LT(kDelay, time_after_run - time_before_run);
144 }
145 
RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory)146 void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
147   scoped_ptr<MessagePump> pump(factory());
148   MessageLoop loop(std::move(pump));
149 
150   // Test that two tasks with different delays run in the right order.
151   int num_tasks = 2;
152   Time run_time1, run_time2;
153 
154   loop.PostDelayedTask(
155       FROM_HERE,
156       Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
157       TimeDelta::FromMilliseconds(200));
158   // If we get a large pause in execution (due to a context switch) here, this
159   // test could fail.
160   loop.PostDelayedTask(
161       FROM_HERE,
162       Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
163       TimeDelta::FromMilliseconds(10));
164 
165   loop.Run();
166   EXPECT_EQ(0, num_tasks);
167 
168   EXPECT_TRUE(run_time2 < run_time1);
169 }
170 
RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory)171 void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
172   scoped_ptr<MessagePump> pump(factory());
173   MessageLoop loop(std::move(pump));
174 
175   // Test that two tasks with the same delay run in the order in which they
176   // were posted.
177   //
178   // NOTE: This is actually an approximate test since the API only takes a
179   // "delay" parameter, so we are not exactly simulating two tasks that get
180   // posted at the exact same time.  It would be nice if the API allowed us to
181   // specify the desired run time.
182 
183   const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
184 
185   int num_tasks = 2;
186   Time run_time1, run_time2;
187 
188   loop.PostDelayedTask(
189       FROM_HERE,
190       Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay);
191   loop.PostDelayedTask(
192       FROM_HERE,
193       Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay);
194 
195   loop.Run();
196   EXPECT_EQ(0, num_tasks);
197 
198   EXPECT_TRUE(run_time1 < run_time2);
199 }
200 
RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory)201 void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
202   scoped_ptr<MessagePump> pump(factory());
203   MessageLoop loop(std::move(pump));
204 
205   // Test that a delayed task still runs after a normal tasks even if the
206   // normal tasks take a long time to run.
207 
208   const TimeDelta kPause = TimeDelta::FromMilliseconds(50);
209 
210   int num_tasks = 2;
211   Time run_time;
212 
213   loop.PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks));
214   loop.PostDelayedTask(
215       FROM_HERE,
216       Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
217       TimeDelta::FromMilliseconds(10));
218 
219   Time time_before_run = Time::Now();
220   loop.Run();
221   Time time_after_run = Time::Now();
222 
223   EXPECT_EQ(0, num_tasks);
224 
225   EXPECT_LT(kPause, time_after_run - time_before_run);
226 }
227 
RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory)228 void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
229   scoped_ptr<MessagePump> pump(factory());
230   MessageLoop loop(std::move(pump));
231 
232   // Test that a delayed task still runs after a pile of normal tasks.  The key
233   // difference between this test and the previous one is that here we return
234   // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
235   // to maybe run the delayed task.  It should know not to do so until the
236   // delayed task's delay has passed.
237 
238   int num_tasks = 11;
239   Time run_time1, run_time2;
240 
241   // Clutter the ML with tasks.
242   for (int i = 1; i < num_tasks; ++i)
243     loop.PostTask(FROM_HERE,
244                   Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
245 
246   loop.PostDelayedTask(
247       FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
248       TimeDelta::FromMilliseconds(1));
249 
250   loop.Run();
251   EXPECT_EQ(0, num_tasks);
252 
253   EXPECT_TRUE(run_time2 > run_time1);
254 }
255 
RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory)256 void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) {
257   scoped_ptr<MessagePump> pump(factory());
258   MessageLoop loop(std::move(pump));
259 
260   // Test that the interval of the timer, used to run the next delayed task, is
261   // set to a value corresponding to when the next delayed task should run.
262 
263   // By setting num_tasks to 1, we ensure that the first task to run causes the
264   // run loop to exit.
265   int num_tasks = 1;
266   Time run_time1, run_time2;
267 
268   loop.PostDelayedTask(
269       FROM_HERE,
270       Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
271       TimeDelta::FromSeconds(1000));
272   loop.PostDelayedTask(
273       FROM_HERE,
274       Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
275       TimeDelta::FromMilliseconds(10));
276 
277   Time start_time = Time::Now();
278 
279   loop.Run();
280   EXPECT_EQ(0, num_tasks);
281 
282   // Ensure that we ran in far less time than the slower timer.
283   TimeDelta total_time = Time::Now() - start_time;
284   EXPECT_GT(5000, total_time.InMilliseconds());
285 
286   // In case both timers somehow run at nearly the same time, sleep a little
287   // and then run all pending to force them both to have run.  This is just
288   // encouraging flakiness if there is any.
289   PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
290   RunLoop().RunUntilIdle();
291 
292   EXPECT_TRUE(run_time1.is_null());
293   EXPECT_FALSE(run_time2.is_null());
294 }
295 
296 // This is used to inject a test point for recording the destructor calls for
297 // Closure objects send to MessageLoop::PostTask(). It is awkward usage since we
298 // are trying to hook the actual destruction, which is not a common operation.
299 class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> {
300  public:
RecordDeletionProbe(RecordDeletionProbe * post_on_delete,bool * was_deleted)301   RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted)
302       : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
303   }
Run()304   void Run() {}
305 
306  private:
307   friend class RefCounted<RecordDeletionProbe>;
308 
~RecordDeletionProbe()309   ~RecordDeletionProbe() {
310     *was_deleted_ = true;
311     if (post_on_delete_.get())
312       MessageLoop::current()->PostTask(
313           FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_.get()));
314   }
315 
316   scoped_refptr<RecordDeletionProbe> post_on_delete_;
317   bool* was_deleted_;
318 };
319 
RunTest_EnsureDeletion(MessagePumpFactory factory)320 void RunTest_EnsureDeletion(MessagePumpFactory factory) {
321   bool a_was_deleted = false;
322   bool b_was_deleted = false;
323   {
324     scoped_ptr<MessagePump> pump(factory());
325     MessageLoop loop(std::move(pump));
326     loop.PostTask(
327         FROM_HERE, Bind(&RecordDeletionProbe::Run,
328                               new RecordDeletionProbe(NULL, &a_was_deleted)));
329     // TODO(ajwong): Do we really need 1000ms here?
330     loop.PostDelayedTask(
331         FROM_HERE, Bind(&RecordDeletionProbe::Run,
332                               new RecordDeletionProbe(NULL, &b_was_deleted)),
333         TimeDelta::FromMilliseconds(1000));
334   }
335   EXPECT_TRUE(a_was_deleted);
336   EXPECT_TRUE(b_was_deleted);
337 }
338 
RunTest_EnsureDeletion_Chain(MessagePumpFactory factory)339 void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory) {
340   bool a_was_deleted = false;
341   bool b_was_deleted = false;
342   bool c_was_deleted = false;
343   {
344     scoped_ptr<MessagePump> pump(factory());
345     MessageLoop loop(std::move(pump));
346     // The scoped_refptr for each of the below is held either by the chained
347     // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
348     RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
349     RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
350     RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
351     loop.PostTask(FROM_HERE, Bind(&RecordDeletionProbe::Run, c));
352   }
353   EXPECT_TRUE(a_was_deleted);
354   EXPECT_TRUE(b_was_deleted);
355   EXPECT_TRUE(c_was_deleted);
356 }
357 
NestingFunc(int * depth)358 void NestingFunc(int* depth) {
359   if (*depth > 0) {
360     *depth -= 1;
361     MessageLoop::current()->PostTask(FROM_HERE,
362                                      Bind(&NestingFunc, depth));
363 
364     MessageLoop::current()->SetNestableTasksAllowed(true);
365     MessageLoop::current()->Run();
366   }
367   MessageLoop::current()->QuitWhenIdle();
368 }
369 
RunTest_Nesting(MessagePumpFactory factory)370 void RunTest_Nesting(MessagePumpFactory factory) {
371   scoped_ptr<MessagePump> pump(factory());
372   MessageLoop loop(std::move(pump));
373 
374   int depth = 100;
375   MessageLoop::current()->PostTask(FROM_HERE,
376                                    Bind(&NestingFunc, &depth));
377   MessageLoop::current()->Run();
378   EXPECT_EQ(depth, 0);
379 }
380 
381 enum TaskType {
382   MESSAGEBOX,
383   ENDDIALOG,
384   RECURSIVE,
385   TIMEDMESSAGELOOP,
386   QUITMESSAGELOOP,
387   ORDERED,
388   PUMPS,
389   SLEEP,
390   RUNS,
391 };
392 
393 struct TaskItem {
TaskItembase::test::TaskItem394   TaskItem(TaskType t, int c, bool s)
395       : type(t),
396         cookie(c),
397         start(s) {
398   }
399 
400   TaskType type;
401   int cookie;
402   bool start;
403 
operator ==base::test::TaskItem404   bool operator == (const TaskItem& other) const {
405     return type == other.type && cookie == other.cookie && start == other.start;
406   }
407 };
408 
operator <<(std::ostream & os,TaskType type)409 std::ostream& operator <<(std::ostream& os, TaskType type) {
410   switch (type) {
411   case MESSAGEBOX:        os << "MESSAGEBOX"; break;
412   case ENDDIALOG:         os << "ENDDIALOG"; break;
413   case RECURSIVE:         os << "RECURSIVE"; break;
414   case TIMEDMESSAGELOOP:  os << "TIMEDMESSAGELOOP"; break;
415   case QUITMESSAGELOOP:   os << "QUITMESSAGELOOP"; break;
416   case ORDERED:          os << "ORDERED"; break;
417   case PUMPS:             os << "PUMPS"; break;
418   case SLEEP:             os << "SLEEP"; break;
419   default:
420     NOTREACHED();
421     os << "Unknown TaskType";
422     break;
423   }
424   return os;
425 }
426 
operator <<(std::ostream & os,const TaskItem & item)427 std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
428   if (item.start)
429     return os << item.type << " " << item.cookie << " starts";
430   else
431     return os << item.type << " " << item.cookie << " ends";
432 }
433 
434 class TaskList {
435  public:
RecordStart(TaskType type,int cookie)436   void RecordStart(TaskType type, int cookie) {
437     TaskItem item(type, cookie, true);
438     DVLOG(1) << item;
439     task_list_.push_back(item);
440   }
441 
RecordEnd(TaskType type,int cookie)442   void RecordEnd(TaskType type, int cookie) {
443     TaskItem item(type, cookie, false);
444     DVLOG(1) << item;
445     task_list_.push_back(item);
446   }
447 
Size()448   size_t Size() {
449     return task_list_.size();
450   }
451 
Get(int n)452   TaskItem Get(int n)  {
453     return task_list_[n];
454   }
455 
456  private:
457   std::vector<TaskItem> task_list_;
458 };
459 
RecursiveFunc(TaskList * order,int cookie,int depth,bool is_reentrant)460 void RecursiveFunc(TaskList* order, int cookie, int depth,
461                    bool is_reentrant) {
462   order->RecordStart(RECURSIVE, cookie);
463   if (depth > 0) {
464     if (is_reentrant)
465       MessageLoop::current()->SetNestableTasksAllowed(true);
466     MessageLoop::current()->PostTask(
467         FROM_HERE,
468         Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
469   }
470   order->RecordEnd(RECURSIVE, cookie);
471 }
472 
QuitFunc(TaskList * order,int cookie)473 void QuitFunc(TaskList* order, int cookie) {
474   order->RecordStart(QUITMESSAGELOOP, cookie);
475   MessageLoop::current()->QuitWhenIdle();
476   order->RecordEnd(QUITMESSAGELOOP, cookie);
477 }
RunTest_RecursiveDenial1(MessagePumpFactory factory)478 void RunTest_RecursiveDenial1(MessagePumpFactory factory) {
479   scoped_ptr<MessagePump> pump(factory());
480   MessageLoop loop(std::move(pump));
481 
482   EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
483   TaskList order;
484   MessageLoop::current()->PostTask(
485       FROM_HERE,
486       Bind(&RecursiveFunc, &order, 1, 2, false));
487   MessageLoop::current()->PostTask(
488       FROM_HERE,
489       Bind(&RecursiveFunc, &order, 2, 2, false));
490   MessageLoop::current()->PostTask(
491       FROM_HERE,
492       Bind(&QuitFunc, &order, 3));
493 
494   MessageLoop::current()->Run();
495 
496   // FIFO order.
497   ASSERT_EQ(14U, order.Size());
498   EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
499   EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
500   EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
501   EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
502   EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
503   EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
504   EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
505   EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
506   EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
507   EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
508   EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
509   EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
510   EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
511   EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
512 }
513 
RecursiveSlowFunc(TaskList * order,int cookie,int depth,bool is_reentrant)514 void RecursiveSlowFunc(TaskList* order, int cookie, int depth,
515                        bool is_reentrant) {
516   RecursiveFunc(order, cookie, depth, is_reentrant);
517   PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
518 }
519 
OrderedFunc(TaskList * order,int cookie)520 void OrderedFunc(TaskList* order, int cookie) {
521   order->RecordStart(ORDERED, cookie);
522   order->RecordEnd(ORDERED, cookie);
523 }
524 
RunTest_RecursiveDenial3(MessagePumpFactory factory)525 void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
526   scoped_ptr<MessagePump> pump(factory());
527   MessageLoop loop(std::move(pump));
528 
529   EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
530   TaskList order;
531   MessageLoop::current()->PostTask(
532       FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false));
533   MessageLoop::current()->PostTask(
534       FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false));
535   MessageLoop::current()->PostDelayedTask(
536       FROM_HERE,
537       Bind(&OrderedFunc, &order, 3),
538       TimeDelta::FromMilliseconds(5));
539   MessageLoop::current()->PostDelayedTask(
540       FROM_HERE,
541       Bind(&QuitFunc, &order, 4),
542       TimeDelta::FromMilliseconds(5));
543 
544   MessageLoop::current()->Run();
545 
546   // FIFO order.
547   ASSERT_EQ(16U, order.Size());
548   EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
549   EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
550   EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
551   EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
552   EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true));
553   EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false));
554   EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true));
555   EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false));
556   EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
557   EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
558   EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true));
559   EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false));
560   EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true));
561   EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false));
562   EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true));
563   EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false));
564 }
565 
RunTest_RecursiveSupport1(MessagePumpFactory factory)566 void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
567   scoped_ptr<MessagePump> pump(factory());
568   MessageLoop loop(std::move(pump));
569 
570   TaskList order;
571   MessageLoop::current()->PostTask(
572       FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true));
573   MessageLoop::current()->PostTask(
574       FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true));
575   MessageLoop::current()->PostTask(
576       FROM_HERE, Bind(&QuitFunc, &order, 3));
577 
578   MessageLoop::current()->Run();
579 
580   // FIFO order.
581   ASSERT_EQ(14U, order.Size());
582   EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
583   EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
584   EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
585   EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
586   EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
587   EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
588   EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
589   EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
590   EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
591   EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
592   EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
593   EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
594   EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
595   EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
596 }
597 
598 // Tests that non nestable tasks run in FIFO if there are no nested loops.
RunTest_NonNestableWithNoNesting(MessagePumpFactory factory)599 void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory) {
600   scoped_ptr<MessagePump> pump(factory());
601   MessageLoop loop(std::move(pump));
602 
603   TaskList order;
604 
605   MessageLoop::current()->PostNonNestableTask(
606       FROM_HERE,
607       Bind(&OrderedFunc, &order, 1));
608   MessageLoop::current()->PostTask(FROM_HERE,
609                                    Bind(&OrderedFunc, &order, 2));
610   MessageLoop::current()->PostTask(FROM_HERE,
611                                    Bind(&QuitFunc, &order, 3));
612   MessageLoop::current()->Run();
613 
614   // FIFO order.
615   ASSERT_EQ(6U, order.Size());
616   EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true));
617   EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false));
618   EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true));
619   EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false));
620   EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
621   EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
622 }
623 
FuncThatPumps(TaskList * order,int cookie)624 void FuncThatPumps(TaskList* order, int cookie) {
625   order->RecordStart(PUMPS, cookie);
626   {
627     MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
628     RunLoop().RunUntilIdle();
629   }
630   order->RecordEnd(PUMPS, cookie);
631 }
632 
SleepFunc(TaskList * order,int cookie,TimeDelta delay)633 void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
634   order->RecordStart(SLEEP, cookie);
635   PlatformThread::Sleep(delay);
636   order->RecordEnd(SLEEP, cookie);
637 }
638 
639 // Tests that non nestable tasks don't run when there's code in the call stack.
RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,bool use_delayed)640 void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
641                                      bool use_delayed) {
642   scoped_ptr<MessagePump> pump(factory());
643   MessageLoop loop(std::move(pump));
644 
645   TaskList order;
646 
647   MessageLoop::current()->PostTask(
648       FROM_HERE,
649       Bind(&FuncThatPumps, &order, 1));
650   if (use_delayed) {
651     MessageLoop::current()->PostNonNestableDelayedTask(
652         FROM_HERE,
653         Bind(&OrderedFunc, &order, 2),
654         TimeDelta::FromMilliseconds(1));
655   } else {
656     MessageLoop::current()->PostNonNestableTask(
657         FROM_HERE,
658         Bind(&OrderedFunc, &order, 2));
659   }
660   MessageLoop::current()->PostTask(FROM_HERE,
661                                    Bind(&OrderedFunc, &order, 3));
662   MessageLoop::current()->PostTask(
663       FROM_HERE,
664       Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50)));
665   MessageLoop::current()->PostTask(FROM_HERE,
666                                    Bind(&OrderedFunc, &order, 5));
667   if (use_delayed) {
668     MessageLoop::current()->PostNonNestableDelayedTask(
669         FROM_HERE,
670         Bind(&QuitFunc, &order, 6),
671         TimeDelta::FromMilliseconds(2));
672   } else {
673     MessageLoop::current()->PostNonNestableTask(
674         FROM_HERE,
675         Bind(&QuitFunc, &order, 6));
676   }
677 
678   MessageLoop::current()->Run();
679 
680   // FIFO order.
681   ASSERT_EQ(12U, order.Size());
682   EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
683   EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true));
684   EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false));
685   EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
686   EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
687   EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true));
688   EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false));
689   EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
690   EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true));
691   EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false));
692   EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
693   EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
694 }
695 
FuncThatRuns(TaskList * order,int cookie,RunLoop * run_loop)696 void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) {
697   order->RecordStart(RUNS, cookie);
698   {
699     MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
700     run_loop->Run();
701   }
702   order->RecordEnd(RUNS, cookie);
703 }
704 
FuncThatQuitsNow()705 void FuncThatQuitsNow() {
706   MessageLoop::current()->QuitNow();
707 }
708 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
RunTest_QuitNow(MessagePumpFactory factory)709 void RunTest_QuitNow(MessagePumpFactory factory) {
710   scoped_ptr<MessagePump> pump(factory());
711   MessageLoop loop(std::move(pump));
712 
713   TaskList order;
714 
715   RunLoop run_loop;
716 
717   MessageLoop::current()->PostTask(FROM_HERE,
718       Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
719   MessageLoop::current()->PostTask(
720       FROM_HERE, Bind(&OrderedFunc, &order, 2));
721   MessageLoop::current()->PostTask(
722       FROM_HERE, Bind(&FuncThatQuitsNow));
723   MessageLoop::current()->PostTask(
724       FROM_HERE, Bind(&OrderedFunc, &order, 3));
725   MessageLoop::current()->PostTask(
726       FROM_HERE, Bind(&FuncThatQuitsNow));
727   MessageLoop::current()->PostTask(
728       FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs
729 
730   MessageLoop::current()->Run();
731 
732   ASSERT_EQ(6U, order.Size());
733   int task_index = 0;
734   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
735   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
736   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
737   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
738   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
739   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
740   EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
741 }
742 
743 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
RunTest_RunLoopQuitTop(MessagePumpFactory factory)744 void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
745   scoped_ptr<MessagePump> pump(factory());
746   MessageLoop loop(std::move(pump));
747 
748   TaskList order;
749 
750   RunLoop outer_run_loop;
751   RunLoop nested_run_loop;
752 
753   MessageLoop::current()->PostTask(FROM_HERE,
754       Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
755   MessageLoop::current()->PostTask(
756       FROM_HERE, outer_run_loop.QuitClosure());
757   MessageLoop::current()->PostTask(
758       FROM_HERE, Bind(&OrderedFunc, &order, 2));
759   MessageLoop::current()->PostTask(
760       FROM_HERE, nested_run_loop.QuitClosure());
761 
762   outer_run_loop.Run();
763 
764   ASSERT_EQ(4U, order.Size());
765   int task_index = 0;
766   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
767   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
768   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
769   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
770   EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
771 }
772 
773 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
RunTest_RunLoopQuitNested(MessagePumpFactory factory)774 void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
775   scoped_ptr<MessagePump> pump(factory());
776   MessageLoop loop(std::move(pump));
777 
778   TaskList order;
779 
780   RunLoop outer_run_loop;
781   RunLoop nested_run_loop;
782 
783   MessageLoop::current()->PostTask(FROM_HERE,
784       Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
785   MessageLoop::current()->PostTask(
786       FROM_HERE, nested_run_loop.QuitClosure());
787   MessageLoop::current()->PostTask(
788       FROM_HERE, Bind(&OrderedFunc, &order, 2));
789   MessageLoop::current()->PostTask(
790       FROM_HERE, outer_run_loop.QuitClosure());
791 
792   outer_run_loop.Run();
793 
794   ASSERT_EQ(4U, order.Size());
795   int task_index = 0;
796   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
797   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
798   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
799   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
800   EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
801 }
802 
803 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
RunTest_RunLoopQuitBogus(MessagePumpFactory factory)804 void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
805   scoped_ptr<MessagePump> pump(factory());
806   MessageLoop loop(std::move(pump));
807 
808   TaskList order;
809 
810   RunLoop outer_run_loop;
811   RunLoop nested_run_loop;
812   RunLoop bogus_run_loop;
813 
814   MessageLoop::current()->PostTask(FROM_HERE,
815       Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
816   MessageLoop::current()->PostTask(
817       FROM_HERE, bogus_run_loop.QuitClosure());
818   MessageLoop::current()->PostTask(
819       FROM_HERE, Bind(&OrderedFunc, &order, 2));
820   MessageLoop::current()->PostTask(
821       FROM_HERE, outer_run_loop.QuitClosure());
822   MessageLoop::current()->PostTask(
823       FROM_HERE, nested_run_loop.QuitClosure());
824 
825   outer_run_loop.Run();
826 
827   ASSERT_EQ(4U, order.Size());
828   int task_index = 0;
829   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
830   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
831   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
832   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
833   EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
834 }
835 
836 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
RunTest_RunLoopQuitDeep(MessagePumpFactory factory)837 void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
838   scoped_ptr<MessagePump> pump(factory());
839   MessageLoop loop(std::move(pump));
840 
841   TaskList order;
842 
843   RunLoop outer_run_loop;
844   RunLoop nested_loop1;
845   RunLoop nested_loop2;
846   RunLoop nested_loop3;
847   RunLoop nested_loop4;
848 
849   MessageLoop::current()->PostTask(FROM_HERE,
850       Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1)));
851   MessageLoop::current()->PostTask(FROM_HERE,
852       Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2)));
853   MessageLoop::current()->PostTask(FROM_HERE,
854       Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3)));
855   MessageLoop::current()->PostTask(FROM_HERE,
856       Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4)));
857   MessageLoop::current()->PostTask(
858       FROM_HERE, Bind(&OrderedFunc, &order, 5));
859   MessageLoop::current()->PostTask(
860       FROM_HERE, outer_run_loop.QuitClosure());
861   MessageLoop::current()->PostTask(
862       FROM_HERE, Bind(&OrderedFunc, &order, 6));
863   MessageLoop::current()->PostTask(
864       FROM_HERE, nested_loop1.QuitClosure());
865   MessageLoop::current()->PostTask(
866       FROM_HERE, Bind(&OrderedFunc, &order, 7));
867   MessageLoop::current()->PostTask(
868       FROM_HERE, nested_loop2.QuitClosure());
869   MessageLoop::current()->PostTask(
870       FROM_HERE, Bind(&OrderedFunc, &order, 8));
871   MessageLoop::current()->PostTask(
872       FROM_HERE, nested_loop3.QuitClosure());
873   MessageLoop::current()->PostTask(
874       FROM_HERE, Bind(&OrderedFunc, &order, 9));
875   MessageLoop::current()->PostTask(
876       FROM_HERE, nested_loop4.QuitClosure());
877   MessageLoop::current()->PostTask(
878       FROM_HERE, Bind(&OrderedFunc, &order, 10));
879 
880   outer_run_loop.Run();
881 
882   ASSERT_EQ(18U, order.Size());
883   int task_index = 0;
884   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
885   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true));
886   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true));
887   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true));
888   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true));
889   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false));
890   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true));
891   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false));
892   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true));
893   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false));
894   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true));
895   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false));
896   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true));
897   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false));
898   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false));
899   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false));
900   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false));
901   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
902   EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
903 }
904 
905 // Tests RunLoopQuit works before RunWithID.
RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory)906 void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
907   scoped_ptr<MessagePump> pump(factory());
908   MessageLoop loop(std::move(pump));
909 
910   TaskList order;
911 
912   RunLoop run_loop;
913 
914   run_loop.Quit();
915 
916   MessageLoop::current()->PostTask(
917       FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs
918   MessageLoop::current()->PostTask(
919       FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs
920 
921   run_loop.Run();
922 
923   ASSERT_EQ(0U, order.Size());
924 }
925 
926 // Tests RunLoopQuit works during RunWithID.
RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory)927 void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
928   scoped_ptr<MessagePump> pump(factory());
929   MessageLoop loop(std::move(pump));
930 
931   TaskList order;
932 
933   RunLoop run_loop;
934 
935   MessageLoop::current()->PostTask(
936       FROM_HERE, Bind(&OrderedFunc, &order, 1));
937   MessageLoop::current()->PostTask(
938       FROM_HERE, run_loop.QuitClosure());
939   MessageLoop::current()->PostTask(
940       FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs
941   MessageLoop::current()->PostTask(
942       FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs
943 
944   run_loop.Run();
945 
946   ASSERT_EQ(2U, order.Size());
947   int task_index = 0;
948   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true));
949   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false));
950   EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
951 }
952 
953 // Tests RunLoopQuit works after RunWithID.
RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory)954 void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) {
955   scoped_ptr<MessagePump> pump(factory());
956   MessageLoop loop(std::move(pump));
957 
958   TaskList order;
959 
960   RunLoop run_loop;
961 
962   MessageLoop::current()->PostTask(FROM_HERE,
963       Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
964   MessageLoop::current()->PostTask(
965       FROM_HERE, Bind(&OrderedFunc, &order, 2));
966   MessageLoop::current()->PostTask(
967       FROM_HERE, Bind(&FuncThatQuitsNow));
968   MessageLoop::current()->PostTask(
969       FROM_HERE, Bind(&OrderedFunc, &order, 3));
970   MessageLoop::current()->PostTask(
971       FROM_HERE, run_loop.QuitClosure()); // has no affect
972   MessageLoop::current()->PostTask(
973       FROM_HERE, Bind(&OrderedFunc, &order, 4));
974   MessageLoop::current()->PostTask(
975       FROM_HERE, Bind(&FuncThatQuitsNow));
976 
977   RunLoop outer_run_loop;
978   outer_run_loop.Run();
979 
980   ASSERT_EQ(8U, order.Size());
981   int task_index = 0;
982   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
983   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
984   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
985   EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
986   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
987   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
988   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true));
989   EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false));
990   EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
991 }
992 
PostNTasksThenQuit(int posts_remaining)993 void PostNTasksThenQuit(int posts_remaining) {
994   if (posts_remaining > 1) {
995     MessageLoop::current()->PostTask(
996         FROM_HERE,
997         Bind(&PostNTasksThenQuit, posts_remaining - 1));
998   } else {
999     MessageLoop::current()->QuitWhenIdle();
1000   }
1001 }
1002 
1003 // There was a bug in the MessagePumpGLib where posting tasks recursively
1004 // caused the message loop to hang, due to the buffer of the internal pipe
1005 // becoming full. Test all MessageLoop types to ensure this issue does not
1006 // exist in other MessagePumps.
1007 //
1008 // On Linux, the pipe buffer size is 64KiB by default. The bug caused one
1009 // byte accumulated in the pipe per two posts, so we should repeat 128K
1010 // times to reproduce the bug.
RunTest_RecursivePosts(MessagePumpFactory factory)1011 void RunTest_RecursivePosts(MessagePumpFactory factory) {
1012   const int kNumTimes = 1 << 17;
1013   scoped_ptr<MessagePump> pump(factory());
1014   MessageLoop loop(std::move(pump));
1015   loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes));
1016   loop.Run();
1017 }
1018 
1019 }  // namespace test
1020 }  // namespace base
1021