message_loop_unittest.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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 <vector> 6 7#include "base/eintr_wrapper.h" 8#include "base/logging.h" 9#include "base/message_loop.h" 10#include "base/platform_thread.h" 11#include "base/ref_counted.h" 12#include "base/task.h" 13#include "base/thread.h" 14#include "testing/gtest/include/gtest/gtest.h" 15 16#if defined(OS_WIN) 17#include "base/message_pump_win.h" 18#include "base/scoped_handle.h" 19#endif 20#if defined(OS_POSIX) 21#include "base/message_pump_libevent.h" 22#endif 23 24using base::Thread; 25using base::Time; 26using base::TimeDelta; 27 28// TODO(darin): Platform-specific MessageLoop tests should be grouped together 29// to avoid chopping this file up with so many #ifdefs. 30 31namespace { 32 33class MessageLoopTest : public testing::Test {}; 34 35class Foo : public base::RefCounted<Foo> { 36 public: 37 Foo() : test_count_(0) { 38 } 39 40 void Test0() { 41 ++test_count_; 42 } 43 44 void Test1ConstRef(const std::string& a) { 45 ++test_count_; 46 result_.append(a); 47 } 48 49 void Test1Ptr(std::string* a) { 50 ++test_count_; 51 result_.append(*a); 52 } 53 54 void Test1Int(int a) { 55 test_count_ += a; 56 } 57 58 void Test2Ptr(std::string* a, std::string* b) { 59 ++test_count_; 60 result_.append(*a); 61 result_.append(*b); 62 } 63 64 void Test2Mixed(const std::string& a, std::string* b) { 65 ++test_count_; 66 result_.append(a); 67 result_.append(*b); 68 } 69 70 int test_count() const { return test_count_; } 71 const std::string& result() const { return result_; } 72 73 private: 74 friend class base::RefCounted<Foo>; 75 76 ~Foo() {} 77 78 int test_count_; 79 std::string result_; 80}; 81 82class QuitMsgLoop : public base::RefCounted<QuitMsgLoop> { 83 public: 84 void QuitNow() { 85 MessageLoop::current()->Quit(); 86 } 87 88 private: 89 friend class base::RefCounted<QuitMsgLoop>; 90 91 ~QuitMsgLoop() {} 92}; 93 94void RunTest_PostTask(MessageLoop::Type message_loop_type) { 95 MessageLoop loop(message_loop_type); 96 97 // Add tests to message loop 98 scoped_refptr<Foo> foo(new Foo()); 99 std::string a("a"), b("b"), c("c"), d("d"); 100 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 101 foo.get(), &Foo::Test0)); 102 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 103 foo.get(), &Foo::Test1ConstRef, a)); 104 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 105 foo.get(), &Foo::Test1Ptr, &b)); 106 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 107 foo.get(), &Foo::Test1Int, 100)); 108 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 109 foo.get(), &Foo::Test2Ptr, &a, &c)); 110 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 111 foo.get(), &Foo::Test2Mixed, a, &d)); 112 113 // After all tests, post a message that will shut down the message loop 114 scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop()); 115 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 116 quit.get(), &QuitMsgLoop::QuitNow)); 117 118 // Now kick things off 119 MessageLoop::current()->Run(); 120 121 EXPECT_EQ(foo->test_count(), 105); 122 EXPECT_EQ(foo->result(), "abacad"); 123} 124 125void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) { 126 MessageLoop loop(message_loop_type); 127 128 // Add tests to message loop 129 scoped_refptr<Foo> foo(new Foo()); 130 std::string a("a"), b("b"), c("c"), d("d"); 131 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 132 foo.get(), &Foo::Test0)); 133 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 134 foo.get(), &Foo::Test1ConstRef, a)); 135 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 136 foo.get(), &Foo::Test1Ptr, &b)); 137 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 138 foo.get(), &Foo::Test1Int, 100)); 139 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 140 foo.get(), &Foo::Test2Ptr, &a, &c)); 141 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 142 foo.get(), &Foo::Test2Mixed, a, &d)); 143 144 // After all tests, post a message that will shut down the message loop 145 scoped_refptr<QuitMsgLoop> quit(new QuitMsgLoop()); 146 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 147 quit.get(), &QuitMsgLoop::QuitNow)); 148 149 // Now kick things off with the SEH block active. 150 MessageLoop::current()->set_exception_restoration(true); 151 MessageLoop::current()->Run(); 152 MessageLoop::current()->set_exception_restoration(false); 153 154 EXPECT_EQ(foo->test_count(), 105); 155 EXPECT_EQ(foo->result(), "abacad"); 156} 157 158// This class runs slowly to simulate a large amount of work being done. 159class SlowTask : public Task { 160 public: 161 SlowTask(int pause_ms, int* quit_counter) 162 : pause_ms_(pause_ms), quit_counter_(quit_counter) { 163 } 164 virtual void Run() { 165 PlatformThread::Sleep(pause_ms_); 166 if (--(*quit_counter_) == 0) 167 MessageLoop::current()->Quit(); 168 } 169 private: 170 int pause_ms_; 171 int* quit_counter_; 172}; 173 174// This class records the time when Run was called in a Time object, which is 175// useful for building a variety of MessageLoop tests. 176class RecordRunTimeTask : public SlowTask { 177 public: 178 RecordRunTimeTask(Time* run_time, int* quit_counter) 179 : SlowTask(10, quit_counter), run_time_(run_time) { 180 } 181 virtual void Run() { 182 *run_time_ = Time::Now(); 183 // Cause our Run function to take some time to execute. As a result we can 184 // count on subsequent RecordRunTimeTask objects running at a future time, 185 // without worry about the resolution of our system clock being an issue. 186 SlowTask::Run(); 187 } 188 private: 189 Time* run_time_; 190}; 191 192void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) { 193 MessageLoop loop(message_loop_type); 194 195 // Test that PostDelayedTask results in a delayed task. 196 197 const int kDelayMS = 100; 198 199 int num_tasks = 1; 200 Time run_time; 201 202 loop.PostDelayedTask( 203 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), kDelayMS); 204 205 Time time_before_run = Time::Now(); 206 loop.Run(); 207 Time time_after_run = Time::Now(); 208 209 EXPECT_EQ(0, num_tasks); 210 EXPECT_LT(kDelayMS, (time_after_run - time_before_run).InMilliseconds()); 211} 212 213void RunTest_PostDelayedTask_InDelayOrder(MessageLoop::Type message_loop_type) { 214 MessageLoop loop(message_loop_type); 215 216 // Test that two tasks with different delays run in the right order. 217 218 int num_tasks = 2; 219 Time run_time1, run_time2; 220 221 loop.PostDelayedTask( 222 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 200); 223 // If we get a large pause in execution (due to a context switch) here, this 224 // test could fail. 225 loop.PostDelayedTask( 226 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10); 227 228 loop.Run(); 229 EXPECT_EQ(0, num_tasks); 230 231 EXPECT_TRUE(run_time2 < run_time1); 232} 233 234void RunTest_PostDelayedTask_InPostOrder(MessageLoop::Type message_loop_type) { 235 MessageLoop loop(message_loop_type); 236 237 // Test that two tasks with the same delay run in the order in which they 238 // were posted. 239 // 240 // NOTE: This is actually an approximate test since the API only takes a 241 // "delay" parameter, so we are not exactly simulating two tasks that get 242 // posted at the exact same time. It would be nice if the API allowed us to 243 // specify the desired run time. 244 245 const int kDelayMS = 100; 246 247 int num_tasks = 2; 248 Time run_time1, run_time2; 249 250 loop.PostDelayedTask( 251 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), kDelayMS); 252 loop.PostDelayedTask( 253 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), kDelayMS); 254 255 loop.Run(); 256 EXPECT_EQ(0, num_tasks); 257 258 EXPECT_TRUE(run_time1 < run_time2); 259} 260 261void RunTest_PostDelayedTask_InPostOrder_2( 262 MessageLoop::Type message_loop_type) { 263 MessageLoop loop(message_loop_type); 264 265 // Test that a delayed task still runs after a normal tasks even if the 266 // normal tasks take a long time to run. 267 268 const int kPauseMS = 50; 269 270 int num_tasks = 2; 271 Time run_time; 272 273 loop.PostTask( 274 FROM_HERE, new SlowTask(kPauseMS, &num_tasks)); 275 loop.PostDelayedTask( 276 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 10); 277 278 Time time_before_run = Time::Now(); 279 loop.Run(); 280 Time time_after_run = Time::Now(); 281 282 EXPECT_EQ(0, num_tasks); 283 284 EXPECT_LT(kPauseMS, (time_after_run - time_before_run).InMilliseconds()); 285} 286 287void RunTest_PostDelayedTask_InPostOrder_3( 288 MessageLoop::Type message_loop_type) { 289 MessageLoop loop(message_loop_type); 290 291 // Test that a delayed task still runs after a pile of normal tasks. The key 292 // difference between this test and the previous one is that here we return 293 // the MessageLoop a lot so we give the MessageLoop plenty of opportunities 294 // to maybe run the delayed task. It should know not to do so until the 295 // delayed task's delay has passed. 296 297 int num_tasks = 11; 298 Time run_time1, run_time2; 299 300 // Clutter the ML with tasks. 301 for (int i = 1; i < num_tasks; ++i) 302 loop.PostTask(FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks)); 303 304 loop.PostDelayedTask( 305 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 1); 306 307 loop.Run(); 308 EXPECT_EQ(0, num_tasks); 309 310 EXPECT_TRUE(run_time2 > run_time1); 311} 312 313void RunTest_PostDelayedTask_SharedTimer(MessageLoop::Type message_loop_type) { 314 MessageLoop loop(message_loop_type); 315 316 // Test that the interval of the timer, used to run the next delayed task, is 317 // set to a value corresponding to when the next delayed task should run. 318 319 // By setting num_tasks to 1, we ensure that the first task to run causes the 320 // run loop to exit. 321 int num_tasks = 1; 322 Time run_time1, run_time2; 323 324 loop.PostDelayedTask( 325 FROM_HERE, new RecordRunTimeTask(&run_time1, &num_tasks), 1000000); 326 loop.PostDelayedTask( 327 FROM_HERE, new RecordRunTimeTask(&run_time2, &num_tasks), 10); 328 329 Time start_time = Time::Now(); 330 331 loop.Run(); 332 EXPECT_EQ(0, num_tasks); 333 334 // Ensure that we ran in far less time than the slower timer. 335 TimeDelta total_time = Time::Now() - start_time; 336 EXPECT_GT(5000, total_time.InMilliseconds()); 337 338 // In case both timers somehow run at nearly the same time, sleep a little 339 // and then run all pending to force them both to have run. This is just 340 // encouraging flakiness if there is any. 341 PlatformThread::Sleep(100); 342 loop.RunAllPending(); 343 344 EXPECT_TRUE(run_time1.is_null()); 345 EXPECT_FALSE(run_time2.is_null()); 346} 347 348#if defined(OS_WIN) 349 350class SubPumpTask : public Task { 351 public: 352 virtual void Run() { 353 MessageLoop::current()->SetNestableTasksAllowed(true); 354 MSG msg; 355 while (GetMessage(&msg, NULL, 0, 0)) { 356 TranslateMessage(&msg); 357 DispatchMessage(&msg); 358 } 359 MessageLoop::current()->Quit(); 360 } 361}; 362 363class SubPumpQuitTask : public Task { 364 public: 365 SubPumpQuitTask() { 366 } 367 virtual void Run() { 368 PostQuitMessage(0); 369 } 370}; 371 372void RunTest_PostDelayedTask_SharedTimer_SubPump() { 373 MessageLoop loop(MessageLoop::TYPE_UI); 374 375 // Test that the interval of the timer, used to run the next delayed task, is 376 // set to a value corresponding to when the next delayed task should run. 377 378 // By setting num_tasks to 1, we ensure that the first task to run causes the 379 // run loop to exit. 380 int num_tasks = 1; 381 Time run_time; 382 383 loop.PostTask(FROM_HERE, new SubPumpTask()); 384 385 // This very delayed task should never run. 386 loop.PostDelayedTask( 387 FROM_HERE, new RecordRunTimeTask(&run_time, &num_tasks), 1000000); 388 389 // This slightly delayed task should run from within SubPumpTask::Run(). 390 loop.PostDelayedTask( 391 FROM_HERE, new SubPumpQuitTask(), 10); 392 393 Time start_time = Time::Now(); 394 395 loop.Run(); 396 EXPECT_EQ(1, num_tasks); 397 398 // Ensure that we ran in far less time than the slower timer. 399 TimeDelta total_time = Time::Now() - start_time; 400 EXPECT_GT(5000, total_time.InMilliseconds()); 401 402 // In case both timers somehow run at nearly the same time, sleep a little 403 // and then run all pending to force them both to have run. This is just 404 // encouraging flakiness if there is any. 405 PlatformThread::Sleep(100); 406 loop.RunAllPending(); 407 408 EXPECT_TRUE(run_time.is_null()); 409} 410 411#endif // defined(OS_WIN) 412 413class RecordDeletionTask : public Task { 414 public: 415 RecordDeletionTask(Task* post_on_delete, bool* was_deleted) 416 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) { 417 } 418 ~RecordDeletionTask() { 419 *was_deleted_ = true; 420 if (post_on_delete_) 421 MessageLoop::current()->PostTask(FROM_HERE, post_on_delete_); 422 } 423 virtual void Run() {} 424 private: 425 Task* post_on_delete_; 426 bool* was_deleted_; 427}; 428 429void RunTest_EnsureTaskDeletion(MessageLoop::Type message_loop_type) { 430 bool a_was_deleted = false; 431 bool b_was_deleted = false; 432 { 433 MessageLoop loop(message_loop_type); 434 loop.PostTask( 435 FROM_HERE, new RecordDeletionTask(NULL, &a_was_deleted)); 436 loop.PostDelayedTask( 437 FROM_HERE, new RecordDeletionTask(NULL, &b_was_deleted), 1000); 438 } 439 EXPECT_TRUE(a_was_deleted); 440 EXPECT_TRUE(b_was_deleted); 441} 442 443void RunTest_EnsureTaskDeletion_Chain(MessageLoop::Type message_loop_type) { 444 bool a_was_deleted = false; 445 bool b_was_deleted = false; 446 bool c_was_deleted = false; 447 { 448 MessageLoop loop(message_loop_type); 449 RecordDeletionTask* a = new RecordDeletionTask(NULL, &a_was_deleted); 450 RecordDeletionTask* b = new RecordDeletionTask(a, &b_was_deleted); 451 RecordDeletionTask* c = new RecordDeletionTask(b, &c_was_deleted); 452 loop.PostTask(FROM_HERE, c); 453 } 454 EXPECT_TRUE(a_was_deleted); 455 EXPECT_TRUE(b_was_deleted); 456 EXPECT_TRUE(c_was_deleted); 457} 458 459class NestingTest : public Task { 460 public: 461 explicit NestingTest(int* depth) : depth_(depth) { 462 } 463 void Run() { 464 if (*depth_ > 0) { 465 *depth_ -= 1; 466 MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(depth_)); 467 468 MessageLoop::current()->SetNestableTasksAllowed(true); 469 MessageLoop::current()->Run(); 470 } 471 MessageLoop::current()->Quit(); 472 } 473 private: 474 int* depth_; 475}; 476 477#if defined(OS_WIN) 478 479LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) { 480 ADD_FAILURE() << "bad exception handler"; 481 ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode); 482 return EXCEPTION_EXECUTE_HANDLER; 483} 484 485// This task throws an SEH exception: initially write to an invalid address. 486// If the right SEH filter is installed, it will fix the error. 487class CrasherTask : public Task { 488 public: 489 // Ctor. If trash_SEH_handler is true, the task will override the unhandled 490 // exception handler with one sure to crash this test. 491 explicit CrasherTask(bool trash_SEH_handler) 492 : trash_SEH_handler_(trash_SEH_handler) { 493 } 494 void Run() { 495 PlatformThread::Sleep(1); 496 if (trash_SEH_handler_) 497 ::SetUnhandledExceptionFilter(&BadExceptionHandler); 498 // Generate a SEH fault. We do it in asm to make sure we know how to undo 499 // the damage. 500 501#if defined(_M_IX86) 502 503 __asm { 504 mov eax, dword ptr [CrasherTask::bad_array_] 505 mov byte ptr [eax], 66 506 } 507 508#elif defined(_M_X64) 509 510 bad_array_[0] = 66; 511 512#else 513#error "needs architecture support" 514#endif 515 516 MessageLoop::current()->Quit(); 517 } 518 // Points the bad array to a valid memory location. 519 static void FixError() { 520 bad_array_ = &valid_store_; 521 } 522 523 private: 524 bool trash_SEH_handler_; 525 static volatile char* bad_array_; 526 static char valid_store_; 527}; 528 529volatile char* CrasherTask::bad_array_ = 0; 530char CrasherTask::valid_store_ = 0; 531 532// This SEH filter fixes the problem and retries execution. Fixing requires 533// that the last instruction: mov eax, [CrasherTask::bad_array_] to be retried 534// so we move the instruction pointer 5 bytes back. 535LONG WINAPI HandleCrasherTaskException(EXCEPTION_POINTERS *ex_info) { 536 if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) 537 return EXCEPTION_EXECUTE_HANDLER; 538 539 CrasherTask::FixError(); 540 541#if defined(_M_IX86) 542 543 ex_info->ContextRecord->Eip -= 5; 544 545#elif defined(_M_X64) 546 547 ex_info->ContextRecord->Rip -= 5; 548 549#endif 550 551 return EXCEPTION_CONTINUE_EXECUTION; 552} 553 554void RunTest_Crasher(MessageLoop::Type message_loop_type) { 555 MessageLoop loop(message_loop_type); 556 557 if (::IsDebuggerPresent()) 558 return; 559 560 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter = 561 ::SetUnhandledExceptionFilter(&HandleCrasherTaskException); 562 563 MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(false)); 564 MessageLoop::current()->set_exception_restoration(true); 565 MessageLoop::current()->Run(); 566 MessageLoop::current()->set_exception_restoration(false); 567 568 ::SetUnhandledExceptionFilter(old_SEH_filter); 569} 570 571void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) { 572 MessageLoop loop(message_loop_type); 573 574 if (::IsDebuggerPresent()) 575 return; 576 577 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter = 578 ::SetUnhandledExceptionFilter(&HandleCrasherTaskException); 579 580 MessageLoop::current()->PostTask(FROM_HERE, new CrasherTask(true)); 581 MessageLoop::current()->set_exception_restoration(true); 582 MessageLoop::current()->Run(); 583 MessageLoop::current()->set_exception_restoration(false); 584 585 ::SetUnhandledExceptionFilter(old_SEH_filter); 586} 587 588#endif // defined(OS_WIN) 589 590void RunTest_Nesting(MessageLoop::Type message_loop_type) { 591 MessageLoop loop(message_loop_type); 592 593 int depth = 100; 594 MessageLoop::current()->PostTask(FROM_HERE, new NestingTest(&depth)); 595 MessageLoop::current()->Run(); 596 EXPECT_EQ(depth, 0); 597} 598 599const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test"; 600 601enum TaskType { 602 MESSAGEBOX, 603 ENDDIALOG, 604 RECURSIVE, 605 TIMEDMESSAGELOOP, 606 QUITMESSAGELOOP, 607 ORDERERD, 608 PUMPS, 609 SLEEP, 610}; 611 612// Saves the order in which the tasks executed. 613struct TaskItem { 614 TaskItem(TaskType t, int c, bool s) 615 : type(t), 616 cookie(c), 617 start(s) { 618 } 619 620 TaskType type; 621 int cookie; 622 bool start; 623 624 bool operator == (const TaskItem& other) const { 625 return type == other.type && cookie == other.cookie && start == other.start; 626 } 627}; 628 629typedef std::vector<TaskItem> TaskList; 630 631std::ostream& operator <<(std::ostream& os, TaskType type) { 632 switch (type) { 633 case MESSAGEBOX: os << "MESSAGEBOX"; break; 634 case ENDDIALOG: os << "ENDDIALOG"; break; 635 case RECURSIVE: os << "RECURSIVE"; break; 636 case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break; 637 case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break; 638 case ORDERERD: os << "ORDERERD"; break; 639 case PUMPS: os << "PUMPS"; break; 640 case SLEEP: os << "SLEEP"; break; 641 default: 642 NOTREACHED(); 643 os << "Unknown TaskType"; 644 break; 645 } 646 return os; 647} 648 649std::ostream& operator <<(std::ostream& os, const TaskItem& item) { 650 if (item.start) 651 return os << item.type << " " << item.cookie << " starts"; 652 else 653 return os << item.type << " " << item.cookie << " ends"; 654} 655 656// Saves the order the tasks ran. 657class OrderedTasks : public Task { 658 public: 659 OrderedTasks(TaskList* order, int cookie) 660 : order_(order), 661 type_(ORDERERD), 662 cookie_(cookie) { 663 } 664 OrderedTasks(TaskList* order, TaskType type, int cookie) 665 : order_(order), 666 type_(type), 667 cookie_(cookie) { 668 } 669 670 void RunStart() { 671 TaskItem item(type_, cookie_, true); 672 DVLOG(1) << item; 673 order_->push_back(item); 674 } 675 void RunEnd() { 676 TaskItem item(type_, cookie_, false); 677 DVLOG(1) << item; 678 order_->push_back(item); 679 } 680 681 virtual void Run() { 682 RunStart(); 683 RunEnd(); 684 } 685 686 protected: 687 TaskList* order() const { 688 return order_; 689 } 690 691 int cookie() const { 692 return cookie_; 693 } 694 695 private: 696 TaskList* order_; 697 TaskType type_; 698 int cookie_; 699}; 700 701#if defined(OS_WIN) 702 703// MessageLoop implicitly start a "modal message loop". Modal dialog boxes, 704// common controls (like OpenFile) and StartDoc printing function can cause 705// implicit message loops. 706class MessageBoxTask : public OrderedTasks { 707 public: 708 MessageBoxTask(TaskList* order, int cookie, bool is_reentrant) 709 : OrderedTasks(order, MESSAGEBOX, cookie), 710 is_reentrant_(is_reentrant) { 711 } 712 713 virtual void Run() { 714 RunStart(); 715 if (is_reentrant_) 716 MessageLoop::current()->SetNestableTasksAllowed(true); 717 MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK); 718 RunEnd(); 719 } 720 721 private: 722 bool is_reentrant_; 723}; 724 725// Will end the MessageBox. 726class EndDialogTask : public OrderedTasks { 727 public: 728 EndDialogTask(TaskList* order, int cookie) 729 : OrderedTasks(order, ENDDIALOG, cookie) { 730 } 731 732 virtual void Run() { 733 RunStart(); 734 HWND window = GetActiveWindow(); 735 if (window != NULL) { 736 EXPECT_NE(EndDialog(window, IDCONTINUE), 0); 737 // Cheap way to signal that the window wasn't found if RunEnd() isn't 738 // called. 739 RunEnd(); 740 } 741 } 742}; 743 744#endif // defined(OS_WIN) 745 746class RecursiveTask : public OrderedTasks { 747 public: 748 RecursiveTask(int depth, TaskList* order, int cookie, bool is_reentrant) 749 : OrderedTasks(order, RECURSIVE, cookie), 750 depth_(depth), 751 is_reentrant_(is_reentrant) { 752 } 753 754 virtual void Run() { 755 RunStart(); 756 if (depth_ > 0) { 757 if (is_reentrant_) 758 MessageLoop::current()->SetNestableTasksAllowed(true); 759 MessageLoop::current()->PostTask(FROM_HERE, 760 new RecursiveTask(depth_ - 1, order(), cookie(), is_reentrant_)); 761 } 762 RunEnd(); 763 } 764 765 private: 766 int depth_; 767 bool is_reentrant_; 768}; 769 770class QuitTask : public OrderedTasks { 771 public: 772 QuitTask(TaskList* order, int cookie) 773 : OrderedTasks(order, QUITMESSAGELOOP, cookie) { 774 } 775 776 virtual void Run() { 777 RunStart(); 778 MessageLoop::current()->Quit(); 779 RunEnd(); 780 } 781}; 782 783class SleepTask : public OrderedTasks { 784 public: 785 SleepTask(TaskList* order, int cookie, int ms) 786 : OrderedTasks(order, SLEEP, cookie), ms_(ms) { 787 } 788 789 virtual void Run() { 790 RunStart(); 791 PlatformThread::Sleep(ms_); 792 RunEnd(); 793 } 794 795 private: 796 int ms_; 797}; 798 799#if defined(OS_WIN) 800 801class Recursive2Tasks : public Task { 802 public: 803 Recursive2Tasks(MessageLoop* target, 804 HANDLE event, 805 bool expect_window, 806 TaskList* order, 807 bool is_reentrant) 808 : target_(target), 809 event_(event), 810 expect_window_(expect_window), 811 order_(order), 812 is_reentrant_(is_reentrant) { 813 } 814 815 virtual void Run() { 816 target_->PostTask(FROM_HERE, 817 new RecursiveTask(2, order_, 1, is_reentrant_)); 818 target_->PostTask(FROM_HERE, 819 new MessageBoxTask(order_, 2, is_reentrant_)); 820 target_->PostTask(FROM_HERE, 821 new RecursiveTask(2, order_, 3, is_reentrant_)); 822 // The trick here is that for recursive task processing, this task will be 823 // ran _inside_ the MessageBox message loop, dismissing the MessageBox 824 // without a chance. 825 // For non-recursive task processing, this will be executed _after_ the 826 // MessageBox will have been dismissed by the code below, where 827 // expect_window_ is true. 828 target_->PostTask(FROM_HERE, new EndDialogTask(order_, 4)); 829 target_->PostTask(FROM_HERE, new QuitTask(order_, 5)); 830 831 // Enforce that every tasks are sent before starting to run the main thread 832 // message loop. 833 ASSERT_TRUE(SetEvent(event_)); 834 835 // Poll for the MessageBox. Don't do this at home! At the speed we do it, 836 // you will never realize one MessageBox was shown. 837 for (; expect_window_;) { 838 HWND window = FindWindow(L"#32770", kMessageBoxTitle); 839 if (window) { 840 // Dismiss it. 841 for (;;) { 842 HWND button = FindWindowEx(window, NULL, L"Button", NULL); 843 if (button != NULL) { 844 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0)); 845 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0)); 846 break; 847 } 848 } 849 break; 850 } 851 } 852 } 853 854 private: 855 MessageLoop* target_; 856 HANDLE event_; 857 TaskList* order_; 858 bool expect_window_; 859 bool is_reentrant_; 860}; 861 862#endif // defined(OS_WIN) 863 864void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) { 865 MessageLoop loop(message_loop_type); 866 867 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); 868 TaskList order; 869 MessageLoop::current()->PostTask(FROM_HERE, 870 new RecursiveTask(2, &order, 1, false)); 871 MessageLoop::current()->PostTask(FROM_HERE, 872 new RecursiveTask(2, &order, 2, false)); 873 MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3)); 874 875 MessageLoop::current()->Run(); 876 877 // FIFO order. 878 ASSERT_EQ(14U, order.size()); 879 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true)); 880 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false)); 881 EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true)); 882 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false)); 883 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true)); 884 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false)); 885 EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true)); 886 EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false)); 887 EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true)); 888 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false)); 889 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true)); 890 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false)); 891 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true)); 892 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false)); 893} 894 895void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) { 896 MessageLoop loop(message_loop_type); 897 898 TaskList order; 899 MessageLoop::current()->PostTask(FROM_HERE, 900 new RecursiveTask(2, &order, 1, true)); 901 MessageLoop::current()->PostTask(FROM_HERE, 902 new RecursiveTask(2, &order, 2, true)); 903 MessageLoop::current()->PostTask(FROM_HERE, 904 new QuitTask(&order, 3)); 905 906 MessageLoop::current()->Run(); 907 908 // FIFO order. 909 ASSERT_EQ(14U, order.size()); 910 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true)); 911 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false)); 912 EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true)); 913 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false)); 914 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true)); 915 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false)); 916 EXPECT_EQ(order[ 6], TaskItem(RECURSIVE, 1, true)); 917 EXPECT_EQ(order[ 7], TaskItem(RECURSIVE, 1, false)); 918 EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true)); 919 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false)); 920 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true)); 921 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false)); 922 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 2, true)); 923 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false)); 924} 925 926#if defined(OS_WIN) 927// TODO(darin): These tests need to be ported since they test critical 928// message loop functionality. 929 930// A side effect of this test is the generation a beep. Sorry. 931void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) { 932 MessageLoop loop(message_loop_type); 933 934 Thread worker("RecursiveDenial2_worker"); 935 Thread::Options options; 936 options.message_loop_type = message_loop_type; 937 ASSERT_EQ(true, worker.StartWithOptions(options)); 938 TaskList order; 939 ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); 940 worker.message_loop()->PostTask(FROM_HERE, 941 new Recursive2Tasks(MessageLoop::current(), 942 event, 943 true, 944 &order, 945 false)); 946 // Let the other thread execute. 947 WaitForSingleObject(event, INFINITE); 948 MessageLoop::current()->Run(); 949 950 ASSERT_EQ(order.size(), 17); 951 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true)); 952 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false)); 953 EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true)); 954 EXPECT_EQ(order[ 3], TaskItem(MESSAGEBOX, 2, false)); 955 EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, true)); 956 EXPECT_EQ(order[ 5], TaskItem(RECURSIVE, 3, false)); 957 // When EndDialogTask is processed, the window is already dismissed, hence no 958 // "end" entry. 959 EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, true)); 960 EXPECT_EQ(order[ 7], TaskItem(QUITMESSAGELOOP, 5, true)); 961 EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, false)); 962 EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 1, true)); 963 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, false)); 964 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 3, true)); 965 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, false)); 966 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 1, true)); 967 EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, false)); 968 EXPECT_EQ(order[15], TaskItem(RECURSIVE, 3, true)); 969 EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, false)); 970} 971 972// A side effect of this test is the generation a beep. Sorry. This test also 973// needs to process windows messages on the current thread. 974void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) { 975 MessageLoop loop(message_loop_type); 976 977 Thread worker("RecursiveSupport2_worker"); 978 Thread::Options options; 979 options.message_loop_type = message_loop_type; 980 ASSERT_EQ(true, worker.StartWithOptions(options)); 981 TaskList order; 982 ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); 983 worker.message_loop()->PostTask(FROM_HERE, 984 new Recursive2Tasks(MessageLoop::current(), 985 event, 986 false, 987 &order, 988 true)); 989 // Let the other thread execute. 990 WaitForSingleObject(event, INFINITE); 991 MessageLoop::current()->Run(); 992 993 ASSERT_EQ(order.size(), 18); 994 EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true)); 995 EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false)); 996 EXPECT_EQ(order[ 2], TaskItem(MESSAGEBOX, 2, true)); 997 // Note that this executes in the MessageBox modal loop. 998 EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 3, true)); 999 EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 3, false)); 1000 EXPECT_EQ(order[ 5], TaskItem(ENDDIALOG, 4, true)); 1001 EXPECT_EQ(order[ 6], TaskItem(ENDDIALOG, 4, false)); 1002 EXPECT_EQ(order[ 7], TaskItem(MESSAGEBOX, 2, false)); 1003 /* The order can subtly change here. The reason is that when RecursiveTask(1) 1004 is called in the main thread, if it is faster than getting to the 1005 PostTask(FROM_HERE, QuitTask) execution, the order of task execution can 1006 change. We don't care anyway that the order isn't correct. 1007 EXPECT_EQ(order[ 8], TaskItem(QUITMESSAGELOOP, 5, true)); 1008 EXPECT_EQ(order[ 9], TaskItem(QUITMESSAGELOOP, 5, false)); 1009 EXPECT_EQ(order[10], TaskItem(RECURSIVE, 1, true)); 1010 EXPECT_EQ(order[11], TaskItem(RECURSIVE, 1, false)); 1011 */ 1012 EXPECT_EQ(order[12], TaskItem(RECURSIVE, 3, true)); 1013 EXPECT_EQ(order[13], TaskItem(RECURSIVE, 3, false)); 1014 EXPECT_EQ(order[14], TaskItem(RECURSIVE, 1, true)); 1015 EXPECT_EQ(order[15], TaskItem(RECURSIVE, 1, false)); 1016 EXPECT_EQ(order[16], TaskItem(RECURSIVE, 3, true)); 1017 EXPECT_EQ(order[17], TaskItem(RECURSIVE, 3, false)); 1018} 1019 1020#endif // defined(OS_WIN) 1021 1022class TaskThatPumps : public OrderedTasks { 1023 public: 1024 TaskThatPumps(TaskList* order, int cookie) 1025 : OrderedTasks(order, PUMPS, cookie) { 1026 } 1027 1028 virtual void Run() { 1029 RunStart(); 1030 bool old_state = MessageLoop::current()->NestableTasksAllowed(); 1031 MessageLoop::current()->SetNestableTasksAllowed(true); 1032 MessageLoop::current()->RunAllPending(); 1033 MessageLoop::current()->SetNestableTasksAllowed(old_state); 1034 RunEnd(); 1035 } 1036}; 1037 1038// Tests that non nestable tasks run in FIFO if there are no nested loops. 1039void RunTest_NonNestableWithNoNesting(MessageLoop::Type message_loop_type) { 1040 MessageLoop loop(message_loop_type); 1041 1042 TaskList order; 1043 1044 Task* task = new OrderedTasks(&order, 1); 1045 MessageLoop::current()->PostNonNestableTask(FROM_HERE, task); 1046 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 2)); 1047 MessageLoop::current()->PostTask(FROM_HERE, new QuitTask(&order, 3)); 1048 MessageLoop::current()->Run(); 1049 1050 // FIFO order. 1051 ASSERT_EQ(6U, order.size()); 1052 EXPECT_EQ(order[ 0], TaskItem(ORDERERD, 1, true)); 1053 EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 1, false)); 1054 EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 2, true)); 1055 EXPECT_EQ(order[ 3], TaskItem(ORDERERD, 2, false)); 1056 EXPECT_EQ(order[ 4], TaskItem(QUITMESSAGELOOP, 3, true)); 1057 EXPECT_EQ(order[ 5], TaskItem(QUITMESSAGELOOP, 3, false)); 1058} 1059 1060// Tests that non nestable tasks don't run when there's code in the call stack. 1061void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type, 1062 bool use_delayed) { 1063 MessageLoop loop(message_loop_type); 1064 1065 TaskList order; 1066 1067 MessageLoop::current()->PostTask(FROM_HERE, 1068 new TaskThatPumps(&order, 1)); 1069 Task* task = new OrderedTasks(&order, 2); 1070 if (use_delayed) { 1071 MessageLoop::current()->PostNonNestableDelayedTask(FROM_HERE, task, 1); 1072 } else { 1073 MessageLoop::current()->PostNonNestableTask(FROM_HERE, task); 1074 } 1075 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 3)); 1076 MessageLoop::current()->PostTask(FROM_HERE, new SleepTask(&order, 4, 50)); 1077 MessageLoop::current()->PostTask(FROM_HERE, new OrderedTasks(&order, 5)); 1078 Task* non_nestable_quit = new QuitTask(&order, 6); 1079 if (use_delayed) { 1080 MessageLoop::current()->PostNonNestableDelayedTask(FROM_HERE, 1081 non_nestable_quit, 1082 2); 1083 } else { 1084 MessageLoop::current()->PostNonNestableTask(FROM_HERE, non_nestable_quit); 1085 } 1086 1087 MessageLoop::current()->Run(); 1088 1089 // FIFO order. 1090 ASSERT_EQ(12U, order.size()); 1091 EXPECT_EQ(order[ 0], TaskItem(PUMPS, 1, true)); 1092 EXPECT_EQ(order[ 1], TaskItem(ORDERERD, 3, true)); 1093 EXPECT_EQ(order[ 2], TaskItem(ORDERERD, 3, false)); 1094 EXPECT_EQ(order[ 3], TaskItem(SLEEP, 4, true)); 1095 EXPECT_EQ(order[ 4], TaskItem(SLEEP, 4, false)); 1096 EXPECT_EQ(order[ 5], TaskItem(ORDERERD, 5, true)); 1097 EXPECT_EQ(order[ 6], TaskItem(ORDERERD, 5, false)); 1098 EXPECT_EQ(order[ 7], TaskItem(PUMPS, 1, false)); 1099 EXPECT_EQ(order[ 8], TaskItem(ORDERERD, 2, true)); 1100 EXPECT_EQ(order[ 9], TaskItem(ORDERERD, 2, false)); 1101 EXPECT_EQ(order[10], TaskItem(QUITMESSAGELOOP, 6, true)); 1102 EXPECT_EQ(order[11], TaskItem(QUITMESSAGELOOP, 6, false)); 1103} 1104 1105#if defined(OS_WIN) 1106 1107class DispatcherImpl : public MessageLoopForUI::Dispatcher { 1108 public: 1109 DispatcherImpl() : dispatch_count_(0) {} 1110 1111 virtual bool Dispatch(const MSG& msg) { 1112 ::TranslateMessage(&msg); 1113 ::DispatchMessage(&msg); 1114 // Do not count WM_TIMER since it is not what we post and it will cause 1115 // flakiness. 1116 if (msg.message != WM_TIMER) 1117 ++dispatch_count_; 1118 // We treat WM_LBUTTONUP as the last message. 1119 return msg.message != WM_LBUTTONUP; 1120 } 1121 1122 int dispatch_count_; 1123}; 1124 1125void RunTest_Dispatcher(MessageLoop::Type message_loop_type) { 1126 MessageLoop loop(message_loop_type); 1127 1128 class MyTask : public Task { 1129 public: 1130 virtual void Run() { 1131 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0); 1132 PostMessage(NULL, WM_LBUTTONUP, 'A', 0); 1133 } 1134 }; 1135 Task* task = new MyTask(); 1136 MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100); 1137 DispatcherImpl dispatcher; 1138 MessageLoopForUI::current()->Run(&dispatcher); 1139 ASSERT_EQ(2, dispatcher.dispatch_count_); 1140} 1141 1142LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) { 1143 if (code == base::MessagePumpForUI::kMessageFilterCode) { 1144 MSG* msg = reinterpret_cast<MSG*>(lparam); 1145 if (msg->message == WM_LBUTTONDOWN) 1146 return TRUE; 1147 } 1148 return FALSE; 1149} 1150 1151void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) { 1152 MessageLoop loop(message_loop_type); 1153 1154 class MyTask : public Task { 1155 public: 1156 virtual void Run() { 1157 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0); 1158 PostMessage(NULL, WM_LBUTTONUP, 'A', 0); 1159 } 1160 }; 1161 Task* task = new MyTask(); 1162 MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 100); 1163 HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER, 1164 MsgFilterProc, 1165 NULL, 1166 GetCurrentThreadId()); 1167 DispatcherImpl dispatcher; 1168 MessageLoopForUI::current()->Run(&dispatcher); 1169 ASSERT_EQ(1, dispatcher.dispatch_count_); 1170 UnhookWindowsHookEx(msg_hook); 1171} 1172 1173class TestIOHandler : public MessageLoopForIO::IOHandler { 1174 public: 1175 TestIOHandler(const wchar_t* name, HANDLE signal, bool wait); 1176 1177 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, 1178 DWORD bytes_transfered, DWORD error); 1179 1180 void Init(); 1181 void WaitForIO(); 1182 OVERLAPPED* context() { return &context_.overlapped; } 1183 DWORD size() { return sizeof(buffer_); } 1184 1185 private: 1186 char buffer_[48]; 1187 MessageLoopForIO::IOContext context_; 1188 HANDLE signal_; 1189 ScopedHandle file_; 1190 bool wait_; 1191}; 1192 1193TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait) 1194 : signal_(signal), wait_(wait) { 1195 memset(buffer_, 0, sizeof(buffer_)); 1196 memset(&context_, 0, sizeof(context_)); 1197 context_.handler = this; 1198 1199 file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 1200 FILE_FLAG_OVERLAPPED, NULL)); 1201 EXPECT_TRUE(file_.IsValid()); 1202} 1203 1204void TestIOHandler::Init() { 1205 MessageLoopForIO::current()->RegisterIOHandler(file_, this); 1206 1207 DWORD read; 1208 EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context())); 1209 EXPECT_EQ(ERROR_IO_PENDING, GetLastError()); 1210 if (wait_) 1211 WaitForIO(); 1212} 1213 1214void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context, 1215 DWORD bytes_transfered, DWORD error) { 1216 ASSERT_TRUE(context == &context_); 1217 ASSERT_TRUE(SetEvent(signal_)); 1218} 1219 1220void TestIOHandler::WaitForIO() { 1221 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this)); 1222 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this)); 1223} 1224 1225class IOHandlerTask : public Task { 1226 public: 1227 explicit IOHandlerTask(TestIOHandler* handler) : handler_(handler) {} 1228 virtual void Run() { 1229 handler_->Init(); 1230 } 1231 1232 private: 1233 TestIOHandler* handler_; 1234}; 1235 1236void RunTest_IOHandler() { 1237 ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL)); 1238 ASSERT_TRUE(callback_called.IsValid()); 1239 1240 const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe"; 1241 ScopedHandle server(CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 1242 0, 0, 0, NULL)); 1243 ASSERT_TRUE(server.IsValid()); 1244 1245 Thread thread("IOHandler test"); 1246 Thread::Options options; 1247 options.message_loop_type = MessageLoop::TYPE_IO; 1248 ASSERT_TRUE(thread.StartWithOptions(options)); 1249 1250 MessageLoop* thread_loop = thread.message_loop(); 1251 ASSERT_TRUE(NULL != thread_loop); 1252 1253 TestIOHandler handler(kPipeName, callback_called, false); 1254 IOHandlerTask* task = new IOHandlerTask(&handler); 1255 thread_loop->PostTask(FROM_HERE, task); 1256 Sleep(100); // Make sure the thread runs and sleeps for lack of work. 1257 1258 const char buffer[] = "Hello there!"; 1259 DWORD written; 1260 EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL)); 1261 1262 DWORD result = WaitForSingleObject(callback_called, 1000); 1263 EXPECT_EQ(WAIT_OBJECT_0, result); 1264 1265 thread.Stop(); 1266} 1267 1268void RunTest_WaitForIO() { 1269 ScopedHandle callback1_called(CreateEvent(NULL, TRUE, FALSE, NULL)); 1270 ScopedHandle callback2_called(CreateEvent(NULL, TRUE, FALSE, NULL)); 1271 ASSERT_TRUE(callback1_called.IsValid()); 1272 ASSERT_TRUE(callback2_called.IsValid()); 1273 1274 const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1"; 1275 const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2"; 1276 ScopedHandle server1(CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 1277 0, 0, 0, NULL)); 1278 ScopedHandle server2(CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 1279 0, 0, 0, NULL)); 1280 ASSERT_TRUE(server1.IsValid()); 1281 ASSERT_TRUE(server2.IsValid()); 1282 1283 Thread thread("IOHandler test"); 1284 Thread::Options options; 1285 options.message_loop_type = MessageLoop::TYPE_IO; 1286 ASSERT_TRUE(thread.StartWithOptions(options)); 1287 1288 MessageLoop* thread_loop = thread.message_loop(); 1289 ASSERT_TRUE(NULL != thread_loop); 1290 1291 TestIOHandler handler1(kPipeName1, callback1_called, false); 1292 TestIOHandler handler2(kPipeName2, callback2_called, true); 1293 IOHandlerTask* task1 = new IOHandlerTask(&handler1); 1294 IOHandlerTask* task2 = new IOHandlerTask(&handler2); 1295 thread_loop->PostTask(FROM_HERE, task1); 1296 Sleep(100); // Make sure the thread runs and sleeps for lack of work. 1297 thread_loop->PostTask(FROM_HERE, task2); 1298 Sleep(100); 1299 1300 // At this time handler1 is waiting to be called, and the thread is waiting 1301 // on the Init method of handler2, filtering only handler2 callbacks. 1302 1303 const char buffer[] = "Hello there!"; 1304 DWORD written; 1305 EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL)); 1306 Sleep(200); 1307 EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) << 1308 "handler1 has not been called"; 1309 1310 EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL)); 1311 1312 HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() }; 1313 DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000); 1314 EXPECT_EQ(WAIT_OBJECT_0, result); 1315 1316 thread.Stop(); 1317} 1318 1319#endif // defined(OS_WIN) 1320 1321} // namespace 1322 1323//----------------------------------------------------------------------------- 1324// Each test is run against each type of MessageLoop. That way we are sure 1325// that message loops work properly in all configurations. Of course, in some 1326// cases, a unit test may only be for a particular type of loop. 1327 1328TEST(MessageLoopTest, PostTask) { 1329 RunTest_PostTask(MessageLoop::TYPE_DEFAULT); 1330 RunTest_PostTask(MessageLoop::TYPE_UI); 1331 RunTest_PostTask(MessageLoop::TYPE_IO); 1332} 1333 1334TEST(MessageLoopTest, PostTask_SEH) { 1335 RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT); 1336 RunTest_PostTask_SEH(MessageLoop::TYPE_UI); 1337 RunTest_PostTask_SEH(MessageLoop::TYPE_IO); 1338} 1339 1340TEST(MessageLoopTest, PostDelayedTask_Basic) { 1341 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT); 1342 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI); 1343 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO); 1344} 1345 1346TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) { 1347 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT); 1348 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI); 1349 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO); 1350} 1351 1352TEST(MessageLoopTest, PostDelayedTask_InPostOrder) { 1353 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT); 1354 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI); 1355 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO); 1356} 1357 1358TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) { 1359 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT); 1360 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI); 1361 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO); 1362} 1363 1364TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) { 1365 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT); 1366 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI); 1367 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO); 1368} 1369 1370TEST(MessageLoopTest, PostDelayedTask_SharedTimer) { 1371 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT); 1372 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI); 1373 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO); 1374} 1375 1376#if defined(OS_WIN) 1377TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) { 1378 RunTest_PostDelayedTask_SharedTimer_SubPump(); 1379} 1380#endif 1381 1382// TODO(darin): MessageLoop does not support deleting all tasks in the 1383// destructor. 1384// Fails, http://crbug.com/50272. 1385TEST(MessageLoopTest, FAILS_EnsureTaskDeletion) { 1386 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_DEFAULT); 1387 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_UI); 1388 RunTest_EnsureTaskDeletion(MessageLoop::TYPE_IO); 1389} 1390 1391// TODO(darin): MessageLoop does not support deleting all tasks in the 1392// destructor. 1393// Fails, http://crbug.com/50272. 1394TEST(MessageLoopTest, FAILS_EnsureTaskDeletion_Chain) { 1395 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_DEFAULT); 1396 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_UI); 1397 RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_IO); 1398} 1399 1400#if defined(OS_WIN) 1401TEST(MessageLoopTest, Crasher) { 1402 RunTest_Crasher(MessageLoop::TYPE_DEFAULT); 1403 RunTest_Crasher(MessageLoop::TYPE_UI); 1404 RunTest_Crasher(MessageLoop::TYPE_IO); 1405} 1406 1407TEST(MessageLoopTest, CrasherNasty) { 1408 RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT); 1409 RunTest_CrasherNasty(MessageLoop::TYPE_UI); 1410 RunTest_CrasherNasty(MessageLoop::TYPE_IO); 1411} 1412#endif // defined(OS_WIN) 1413 1414TEST(MessageLoopTest, Nesting) { 1415 RunTest_Nesting(MessageLoop::TYPE_DEFAULT); 1416 RunTest_Nesting(MessageLoop::TYPE_UI); 1417 RunTest_Nesting(MessageLoop::TYPE_IO); 1418} 1419 1420TEST(MessageLoopTest, RecursiveDenial1) { 1421 RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT); 1422 RunTest_RecursiveDenial1(MessageLoop::TYPE_UI); 1423 RunTest_RecursiveDenial1(MessageLoop::TYPE_IO); 1424} 1425 1426TEST(MessageLoopTest, RecursiveSupport1) { 1427 RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT); 1428 RunTest_RecursiveSupport1(MessageLoop::TYPE_UI); 1429 RunTest_RecursiveSupport1(MessageLoop::TYPE_IO); 1430} 1431 1432#if defined(OS_WIN) 1433// This test occasionally hangs http://crbug.com/44567 1434TEST(MessageLoopTest, DISABLED_RecursiveDenial2) { 1435 RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT); 1436 RunTest_RecursiveDenial2(MessageLoop::TYPE_UI); 1437 RunTest_RecursiveDenial2(MessageLoop::TYPE_IO); 1438} 1439 1440TEST(MessageLoopTest, RecursiveSupport2) { 1441 // This test requires a UI loop 1442 RunTest_RecursiveSupport2(MessageLoop::TYPE_UI); 1443} 1444#endif // defined(OS_WIN) 1445 1446TEST(MessageLoopTest, NonNestableWithNoNesting) { 1447 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT); 1448 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI); 1449 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO); 1450} 1451 1452TEST(MessageLoopTest, NonNestableInNestedLoop) { 1453 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false); 1454 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false); 1455 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false); 1456} 1457 1458TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) { 1459 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true); 1460 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true); 1461 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true); 1462} 1463 1464class DummyTask : public Task { 1465 public: 1466 explicit DummyTask(int num_tasks) : num_tasks_(num_tasks) {} 1467 1468 virtual void Run() { 1469 if (num_tasks_ > 1) { 1470 MessageLoop::current()->PostTask( 1471 FROM_HERE, 1472 new DummyTask(num_tasks_ - 1)); 1473 } else { 1474 MessageLoop::current()->Quit(); 1475 } 1476 } 1477 1478 private: 1479 const int num_tasks_; 1480}; 1481 1482class DummyTaskObserver : public MessageLoop::TaskObserver { 1483 public: 1484 explicit DummyTaskObserver(int num_tasks) 1485 : num_tasks_started_(0), 1486 num_tasks_processed_(0), 1487 num_tasks_(num_tasks) {} 1488 1489 virtual ~DummyTaskObserver() {} 1490 1491 virtual void WillProcessTask(const Task* task) { 1492 num_tasks_started_++; 1493 EXPECT_TRUE(task != NULL); 1494 EXPECT_LE(num_tasks_started_, num_tasks_); 1495 EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1); 1496 } 1497 1498 virtual void DidProcessTask(const Task* task) { 1499 num_tasks_processed_++; 1500 EXPECT_TRUE(task != NULL); 1501 EXPECT_LE(num_tasks_started_, num_tasks_); 1502 EXPECT_EQ(num_tasks_started_, num_tasks_processed_); 1503 } 1504 1505 int num_tasks_started() const { return num_tasks_started_; } 1506 int num_tasks_processed() const { return num_tasks_processed_; } 1507 1508 private: 1509 int num_tasks_started_; 1510 int num_tasks_processed_; 1511 const int num_tasks_; 1512 1513 DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver); 1514}; 1515 1516TEST(MessageLoopTest, TaskObserver) { 1517 const int kNumTasks = 6; 1518 DummyTaskObserver observer(kNumTasks); 1519 1520 MessageLoop loop; 1521 loop.AddTaskObserver(&observer); 1522 loop.PostTask(FROM_HERE, new DummyTask(kNumTasks)); 1523 loop.Run(); 1524 loop.RemoveTaskObserver(&observer); 1525 1526 EXPECT_EQ(kNumTasks, observer.num_tasks_started()); 1527 EXPECT_EQ(kNumTasks, observer.num_tasks_processed()); 1528} 1529 1530#if defined(OS_WIN) 1531TEST(MessageLoopTest, Dispatcher) { 1532 // This test requires a UI loop 1533 RunTest_Dispatcher(MessageLoop::TYPE_UI); 1534} 1535 1536TEST(MessageLoopTest, DispatcherWithMessageHook) { 1537 // This test requires a UI loop 1538 RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI); 1539} 1540 1541TEST(MessageLoopTest, IOHandler) { 1542 RunTest_IOHandler(); 1543} 1544 1545TEST(MessageLoopTest, WaitForIO) { 1546 RunTest_WaitForIO(); 1547} 1548 1549TEST(MessageLoopTest, HighResolutionTimer) { 1550 MessageLoop loop; 1551 1552 const int kFastTimerMs = 5; 1553 const int kSlowTimerMs = 100; 1554 1555 EXPECT_EQ(false, loop.high_resolution_timers_enabled()); 1556 1557 // Post a fast task to enable the high resolution timers. 1558 loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kFastTimerMs); 1559 loop.Run(); 1560 EXPECT_EQ(true, loop.high_resolution_timers_enabled()); 1561 1562 // Post a slow task and verify high resolution timers 1563 // are still enabled. 1564 loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs); 1565 loop.Run(); 1566 EXPECT_EQ(true, loop.high_resolution_timers_enabled()); 1567 1568 // Wait for a while so that high-resolution mode elapses. 1569 Sleep(MessageLoop::kHighResolutionTimerModeLeaseTimeMs); 1570 1571 // Post a slow task to disable the high resolution timers. 1572 loop.PostDelayedTask(FROM_HERE, new DummyTask(1), kSlowTimerMs); 1573 loop.Run(); 1574 EXPECT_EQ(false, loop.high_resolution_timers_enabled()); 1575} 1576 1577#endif // defined(OS_WIN) 1578 1579#if defined(OS_POSIX) && !defined(OS_NACL) 1580 1581namespace { 1582 1583class QuitDelegate : public base::MessagePumpLibevent::Watcher { 1584 public: 1585 virtual void OnFileCanWriteWithoutBlocking(int fd) { 1586 MessageLoop::current()->Quit(); 1587 } 1588 virtual void OnFileCanReadWithoutBlocking(int fd) { 1589 MessageLoop::current()->Quit(); 1590 } 1591}; 1592 1593TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) { 1594 // Simulate a MessageLoop that dies before an FileDescriptorWatcher. 1595 // This could happen when people use the Singleton pattern or atexit. 1596 1597 // Create a file descriptor. Doesn't need to be readable or writable, 1598 // as we don't need to actually get any notifications. 1599 // pipe() is just the easiest way to do it. 1600 int pipefds[2]; 1601 int err = pipe(pipefds); 1602 ASSERT_EQ(0, err); 1603 int fd = pipefds[1]; 1604 { 1605 // Arrange for controller to live longer than message loop. 1606 base::MessagePumpLibevent::FileDescriptorWatcher controller; 1607 { 1608 MessageLoopForIO message_loop; 1609 1610 QuitDelegate delegate; 1611 message_loop.WatchFileDescriptor(fd, 1612 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate); 1613 // and don't run the message loop, just destroy it. 1614 } 1615 } 1616 if (HANDLE_EINTR(close(pipefds[0])) < 0) 1617 PLOG(ERROR) << "close"; 1618 if (HANDLE_EINTR(close(pipefds[1])) < 0) 1619 PLOG(ERROR) << "close"; 1620} 1621 1622TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) { 1623 // Verify that it's ok to call StopWatchingFileDescriptor(). 1624 // (Errors only showed up in valgrind.) 1625 int pipefds[2]; 1626 int err = pipe(pipefds); 1627 ASSERT_EQ(0, err); 1628 int fd = pipefds[1]; 1629 { 1630 // Arrange for message loop to live longer than controller. 1631 MessageLoopForIO message_loop; 1632 { 1633 base::MessagePumpLibevent::FileDescriptorWatcher controller; 1634 1635 QuitDelegate delegate; 1636 message_loop.WatchFileDescriptor(fd, 1637 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate); 1638 controller.StopWatchingFileDescriptor(); 1639 } 1640 } 1641 if (HANDLE_EINTR(close(pipefds[0])) < 0) 1642 PLOG(ERROR) << "close"; 1643 if (HANDLE_EINTR(close(pipefds[1])) < 0) 1644 PLOG(ERROR) << "close"; 1645} 1646 1647} // namespace 1648 1649#endif // defined(OS_POSIX) && !defined(OS_NACL) 1650 1651namespace { 1652class RunAtDestructionTask : public Task { 1653 public: 1654 RunAtDestructionTask(bool* task_destroyed, bool* destruction_observer_called) 1655 : task_destroyed_(task_destroyed), 1656 destruction_observer_called_(destruction_observer_called) { 1657 } 1658 ~RunAtDestructionTask() { 1659 EXPECT_FALSE(*destruction_observer_called_); 1660 *task_destroyed_ = true; 1661 } 1662 virtual void Run() { 1663 // This task should never run. 1664 ADD_FAILURE(); 1665 } 1666 private: 1667 bool* task_destroyed_; 1668 bool* destruction_observer_called_; 1669}; 1670 1671class MLDestructionObserver : public MessageLoop::DestructionObserver { 1672 public: 1673 MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called) 1674 : task_destroyed_(task_destroyed), 1675 destruction_observer_called_(destruction_observer_called), 1676 task_destroyed_before_message_loop_(false) { 1677 } 1678 virtual void WillDestroyCurrentMessageLoop() { 1679 task_destroyed_before_message_loop_ = *task_destroyed_; 1680 *destruction_observer_called_ = true; 1681 } 1682 bool task_destroyed_before_message_loop() const { 1683 return task_destroyed_before_message_loop_; 1684 } 1685 private: 1686 bool* task_destroyed_; 1687 bool* destruction_observer_called_; 1688 bool task_destroyed_before_message_loop_; 1689}; 1690 1691} // namespace 1692 1693TEST(MessageLoopTest, DestructionObserverTest) { 1694 // Verify that the destruction observer gets called at the very end (after 1695 // all the pending tasks have been destroyed). 1696 MessageLoop* loop = new MessageLoop; 1697 const int kDelayMS = 100; 1698 1699 bool task_destroyed = false; 1700 bool destruction_observer_called = false; 1701 1702 MLDestructionObserver observer(&task_destroyed, &destruction_observer_called); 1703 loop->AddDestructionObserver(&observer); 1704 loop->PostDelayedTask( 1705 FROM_HERE, 1706 new RunAtDestructionTask(&task_destroyed, &destruction_observer_called), 1707 kDelayMS); 1708 delete loop; 1709 EXPECT_TRUE(observer.task_destroyed_before_message_loop()); 1710 // The task should have been destroyed when we deleted the loop. 1711 EXPECT_TRUE(task_destroyed); 1712 EXPECT_TRUE(destruction_observer_called); 1713} 1714