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