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: 25 Foo() : test_count_(0) { 26 } 27 28 void Test0() { 29 ++test_count_; 30 } 31 32 void Test1ConstRef(const std::string& a) { 33 ++test_count_; 34 result_.append(a); 35 } 36 37 void Test1Ptr(std::string* a) { 38 ++test_count_; 39 result_.append(*a); 40 } 41 42 void Test1Int(int a) { 43 test_count_ += a; 44 } 45 46 void Test2Ptr(std::string* a, std::string* b) { 47 ++test_count_; 48 result_.append(*a); 49 result_.append(*b); 50 } 51 52 void Test2Mixed(const std::string& a, std::string* b) { 53 ++test_count_; 54 result_.append(a); 55 result_.append(*b); 56 } 57 58 int test_count() const { return test_count_; } 59 const std::string& result() const { return result_; } 60 61 private: 62 friend class RefCounted<Foo>; 63 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. 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? 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 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 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 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 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 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 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 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: 301 RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted) 302 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) { 303 } 304 void Run() {} 305 306 private: 307 friend class RefCounted<RecordDeletionProbe>; 308 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 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 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 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 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 { 394 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 404 bool operator == (const TaskItem& other) const { 405 return type == other.type && cookie == other.cookie && start == other.start; 406 } 407 }; 408 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 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: 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 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 448 size_t Size() { 449 return task_list_.size(); 450 } 451 452 TaskItem Get(int n) { 453 return task_list_[n]; 454 } 455 456 private: 457 std::vector<TaskItem> task_list_; 458 }; 459 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 473 void QuitFunc(TaskList* order, int cookie) { 474 order->RecordStart(QUITMESSAGELOOP, cookie); 475 MessageLoop::current()->QuitWhenIdle(); 476 order->RecordEnd(QUITMESSAGELOOP, cookie); 477 } 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 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 520 void OrderedFunc(TaskList* order, int cookie) { 521 order->RecordStart(ORDERED, cookie); 522 order->RecordEnd(ORDERED, cookie); 523 } 524 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 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. 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 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 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. 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 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 705 void FuncThatQuitsNow() { 706 MessageLoop::current()->QuitNow(); 707 } 708 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. 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. 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. 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. 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. 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. 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. 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. 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 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. 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