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