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: 20 Foo() : test_count_(0) { 21 } 22 23 void Test0() { 24 ++test_count_; 25 } 26 27 void Test1ConstRef(const std::string& a) { 28 ++test_count_; 29 result_.append(a); 30 } 31 32 void Test1Ptr(std::string* a) { 33 ++test_count_; 34 result_.append(*a); 35 } 36 37 void Test1Int(int a) { 38 test_count_ += a; 39 } 40 41 void Test2Ptr(std::string* a, std::string* b) { 42 ++test_count_; 43 result_.append(*a); 44 result_.append(*b); 45 } 46 47 void Test2Mixed(const std::string& a, std::string* b) { 48 ++test_count_; 49 result_.append(a); 50 result_.append(*b); 51 } 52 53 int test_count() const { return test_count_; } 54 const std::string& result() const { return result_; } 55 56 private: 57 friend class RefCounted<Foo>; 58 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. 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? 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 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 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 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 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 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 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 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: 295 RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted) 296 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) { 297 } 298 void Run() {} 299 300 private: 301 friend class RefCounted<RecordDeletionProbe>; 302 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 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 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 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 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 { 388 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 398 bool operator == (const TaskItem& other) const { 399 return type == other.type && cookie == other.cookie && start == other.start; 400 } 401 }; 402 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 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: 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 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 442 size_t Size() { 443 return task_list_.size(); 444 } 445 446 TaskItem Get(int n) { 447 return task_list_[n]; 448 } 449 450 private: 451 std::vector<TaskItem> task_list_; 452 }; 453 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 467 void QuitFunc(TaskList* order, int cookie) { 468 order->RecordStart(QUITMESSAGELOOP, cookie); 469 MessageLoop::current()->QuitWhenIdle(); 470 order->RecordEnd(QUITMESSAGELOOP, cookie); 471 } 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 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 514 void OrderedFunc(TaskList* order, int cookie) { 515 order->RecordStart(ORDERED, cookie); 516 order->RecordEnd(ORDERED, cookie); 517 } 518 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 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. 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 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 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. 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 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 699 void FuncThatQuitsNow() { 700 MessageLoop::current()->QuitNow(); 701 } 702 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. 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. 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. 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. 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. 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. 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. 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. 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 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. 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