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