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 #include "base/threading/thread_task_runner_handle.h" 19 20 namespace base { 21 namespace test { 22 23 namespace { 24 25 class Foo : public RefCounted<Foo> { 26 public: 27 Foo() : test_count_(0) { 28 } 29 30 void Test0() { 31 ++test_count_; 32 } 33 34 void Test1ConstRef(const std::string& a) { 35 ++test_count_; 36 result_.append(a); 37 } 38 39 void Test1Ptr(std::string* a) { 40 ++test_count_; 41 result_.append(*a); 42 } 43 44 void Test1Int(int a) { 45 test_count_ += a; 46 } 47 48 void Test2Ptr(std::string* a, std::string* b) { 49 ++test_count_; 50 result_.append(*a); 51 result_.append(*b); 52 } 53 54 void Test2Mixed(const std::string& a, std::string* b) { 55 ++test_count_; 56 result_.append(a); 57 result_.append(*b); 58 } 59 60 int test_count() const { return test_count_; } 61 const std::string& result() const { return result_; } 62 63 private: 64 friend class RefCounted<Foo>; 65 66 ~Foo() {} 67 68 int test_count_; 69 std::string result_; 70 71 DISALLOW_COPY_AND_ASSIGN(Foo); 72 }; 73 74 // This function runs slowly to simulate a large amount of work being done. 75 void SlowFunc(TimeDelta pause, int* quit_counter) { 76 PlatformThread::Sleep(pause); 77 if (--(*quit_counter) == 0) 78 MessageLoop::current()->QuitWhenIdle(); 79 } 80 81 // This function records the time when Run was called in a Time object, which is 82 // useful for building a variety of MessageLoop tests. 83 // TODO(sky): remove? 84 void RecordRunTimeFunc(Time* run_time, int* quit_counter) { 85 *run_time = Time::Now(); 86 87 // Cause our Run function to take some time to execute. As a result we can 88 // count on subsequent RecordRunTimeFunc()s running at a future time, 89 // without worry about the resolution of our system clock being an issue. 90 SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter); 91 } 92 93 } // namespace 94 95 void RunTest_PostTask(MessagePumpFactory factory) { 96 std::unique_ptr<MessagePump> pump(factory()); 97 MessageLoop loop(std::move(pump)); 98 // Add tests to message loop 99 scoped_refptr<Foo> foo(new Foo()); 100 std::string a("a"), b("b"), c("c"), d("d"); 101 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&Foo::Test0, foo)); 102 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 103 Bind(&Foo::Test1ConstRef, foo, a)); 104 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 105 Bind(&Foo::Test1Ptr, foo, &b)); 106 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 107 Bind(&Foo::Test1Int, foo, 100)); 108 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 109 Bind(&Foo::Test2Ptr, foo, &a, &c)); 110 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 111 Bind(&Foo::Test2Mixed, foo, a, &d)); 112 // After all tests, post a message that will shut down the message loop 113 ThreadTaskRunnerHandle::Get()->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 ThreadTaskRunnerHandle::Get()->PostTask( 306 FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_)); 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 ThreadTaskRunnerHandle::Get()->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 ThreadTaskRunnerHandle::Get()->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 ThreadTaskRunnerHandle::Get()->PostTask( 407 FROM_HERE, Bind(&ExpectOneBeginNestedLoop, observer)); 408 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, nested_loop.QuitClosure()); 409 nested_loop.Run(); 410 411 // Quitting message loops doesn't change the begin count. 412 EXPECT_EQ(1, observer->begin_nested_loop_count()); 413 414 quit_outer_loop.Run(); 415 } 416 417 // Tests that a NestingObserver is notified when a nested message loop begins. 418 void RunTest_NestingObserver(MessagePumpFactory factory) { 419 std::unique_ptr<MessagePump> pump(factory()); 420 MessageLoop outer_loop(std::move(pump)); 421 422 // Observe the outer loop for nested message loops beginning. 423 TestNestingObserver nesting_observer; 424 outer_loop.AddNestingObserver(&nesting_observer); 425 426 // Post a task that runs a nested message loop. 427 outer_loop.task_runner()->PostTask(FROM_HERE, 428 Bind(&RunNestedLoop, &nesting_observer, 429 outer_loop.QuitWhenIdleClosure())); 430 RunLoop().Run(); 431 432 outer_loop.RemoveNestingObserver(&nesting_observer); 433 } 434 435 enum TaskType { 436 MESSAGEBOX, 437 ENDDIALOG, 438 RECURSIVE, 439 TIMEDMESSAGELOOP, 440 QUITMESSAGELOOP, 441 ORDERED, 442 PUMPS, 443 SLEEP, 444 RUNS, 445 }; 446 447 struct TaskItem { 448 TaskItem(TaskType t, int c, bool s) 449 : type(t), 450 cookie(c), 451 start(s) { 452 } 453 454 TaskType type; 455 int cookie; 456 bool start; 457 458 bool operator == (const TaskItem& other) const { 459 return type == other.type && cookie == other.cookie && start == other.start; 460 } 461 }; 462 463 std::ostream& operator <<(std::ostream& os, TaskType type) { 464 switch (type) { 465 case MESSAGEBOX: os << "MESSAGEBOX"; break; 466 case ENDDIALOG: os << "ENDDIALOG"; break; 467 case RECURSIVE: os << "RECURSIVE"; break; 468 case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break; 469 case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break; 470 case ORDERED: os << "ORDERED"; break; 471 case PUMPS: os << "PUMPS"; break; 472 case SLEEP: os << "SLEEP"; break; 473 default: 474 NOTREACHED(); 475 os << "Unknown TaskType"; 476 break; 477 } 478 return os; 479 } 480 481 std::ostream& operator <<(std::ostream& os, const TaskItem& item) { 482 if (item.start) 483 return os << item.type << " " << item.cookie << " starts"; 484 else 485 return os << item.type << " " << item.cookie << " ends"; 486 } 487 488 class TaskList { 489 public: 490 void RecordStart(TaskType type, int cookie) { 491 TaskItem item(type, cookie, true); 492 DVLOG(1) << item; 493 task_list_.push_back(item); 494 } 495 496 void RecordEnd(TaskType type, int cookie) { 497 TaskItem item(type, cookie, false); 498 DVLOG(1) << item; 499 task_list_.push_back(item); 500 } 501 502 size_t Size() { 503 return task_list_.size(); 504 } 505 506 TaskItem Get(int n) { 507 return task_list_[n]; 508 } 509 510 private: 511 std::vector<TaskItem> task_list_; 512 }; 513 514 void RecursiveFunc(TaskList* order, int cookie, int depth, 515 bool is_reentrant) { 516 order->RecordStart(RECURSIVE, cookie); 517 if (depth > 0) { 518 if (is_reentrant) 519 MessageLoop::current()->SetNestableTasksAllowed(true); 520 ThreadTaskRunnerHandle::Get()->PostTask( 521 FROM_HERE, 522 Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant)); 523 } 524 order->RecordEnd(RECURSIVE, cookie); 525 } 526 527 void QuitFunc(TaskList* order, int cookie) { 528 order->RecordStart(QUITMESSAGELOOP, cookie); 529 MessageLoop::current()->QuitWhenIdle(); 530 order->RecordEnd(QUITMESSAGELOOP, cookie); 531 } 532 void RunTest_RecursiveDenial1(MessagePumpFactory factory) { 533 std::unique_ptr<MessagePump> pump(factory()); 534 MessageLoop loop(std::move(pump)); 535 536 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); 537 TaskList order; 538 ThreadTaskRunnerHandle::Get()->PostTask( 539 FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, false)); 540 ThreadTaskRunnerHandle::Get()->PostTask( 541 FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, false)); 542 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 543 Bind(&QuitFunc, &order, 3)); 544 545 RunLoop().Run(); 546 547 // FIFO order. 548 ASSERT_EQ(14U, order.Size()); 549 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); 550 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); 551 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); 552 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); 553 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); 554 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); 555 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); 556 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); 557 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); 558 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); 559 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); 560 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); 561 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); 562 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); 563 } 564 565 void RecursiveSlowFunc(TaskList* order, int cookie, int depth, 566 bool is_reentrant) { 567 RecursiveFunc(order, cookie, depth, is_reentrant); 568 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); 569 } 570 571 void OrderedFunc(TaskList* order, int cookie) { 572 order->RecordStart(ORDERED, cookie); 573 order->RecordEnd(ORDERED, cookie); 574 } 575 576 void RunTest_RecursiveDenial3(MessagePumpFactory factory) { 577 std::unique_ptr<MessagePump> pump(factory()); 578 MessageLoop loop(std::move(pump)); 579 580 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); 581 TaskList order; 582 ThreadTaskRunnerHandle::Get()->PostTask( 583 FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false)); 584 ThreadTaskRunnerHandle::Get()->PostTask( 585 FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false)); 586 ThreadTaskRunnerHandle::Get()->PostDelayedTask( 587 FROM_HERE, Bind(&OrderedFunc, &order, 3), TimeDelta::FromMilliseconds(5)); 588 ThreadTaskRunnerHandle::Get()->PostDelayedTask( 589 FROM_HERE, Bind(&QuitFunc, &order, 4), TimeDelta::FromMilliseconds(5)); 590 591 RunLoop().Run(); 592 593 // FIFO order. 594 ASSERT_EQ(16U, order.Size()); 595 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); 596 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); 597 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); 598 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); 599 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true)); 600 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false)); 601 EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true)); 602 EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false)); 603 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); 604 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); 605 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true)); 606 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false)); 607 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true)); 608 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false)); 609 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true)); 610 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false)); 611 } 612 613 void RunTest_RecursiveSupport1(MessagePumpFactory factory) { 614 std::unique_ptr<MessagePump> pump(factory()); 615 MessageLoop loop(std::move(pump)); 616 617 TaskList order; 618 ThreadTaskRunnerHandle::Get()->PostTask( 619 FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true)); 620 ThreadTaskRunnerHandle::Get()->PostTask( 621 FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true)); 622 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 623 Bind(&QuitFunc, &order, 3)); 624 625 RunLoop().Run(); 626 627 // FIFO order. 628 ASSERT_EQ(14U, order.Size()); 629 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); 630 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); 631 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); 632 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); 633 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); 634 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); 635 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); 636 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); 637 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); 638 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); 639 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); 640 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); 641 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); 642 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); 643 } 644 645 // Tests that non nestable tasks run in FIFO if there are no nested loops. 646 void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory) { 647 std::unique_ptr<MessagePump> pump(factory()); 648 MessageLoop loop(std::move(pump)); 649 650 TaskList order; 651 652 ThreadTaskRunnerHandle::Get()->PostNonNestableTask( 653 FROM_HERE, Bind(&OrderedFunc, &order, 1)); 654 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 655 Bind(&OrderedFunc, &order, 2)); 656 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 657 Bind(&QuitFunc, &order, 3)); 658 RunLoop().Run(); 659 660 // FIFO order. 661 ASSERT_EQ(6U, order.Size()); 662 EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true)); 663 EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false)); 664 EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true)); 665 EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false)); 666 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); 667 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); 668 } 669 670 void FuncThatPumps(TaskList* order, int cookie) { 671 order->RecordStart(PUMPS, cookie); 672 { 673 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); 674 RunLoop().RunUntilIdle(); 675 } 676 order->RecordEnd(PUMPS, cookie); 677 } 678 679 void SleepFunc(TaskList* order, int cookie, TimeDelta delay) { 680 order->RecordStart(SLEEP, cookie); 681 PlatformThread::Sleep(delay); 682 order->RecordEnd(SLEEP, cookie); 683 } 684 685 // Tests that non nestable tasks don't run when there's code in the call stack. 686 void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory) { 687 std::unique_ptr<MessagePump> pump(factory()); 688 MessageLoop loop(std::move(pump)); 689 690 TaskList order; 691 692 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 693 Bind(&FuncThatPumps, &order, 1)); 694 ThreadTaskRunnerHandle::Get()->PostNonNestableTask( 695 FROM_HERE, Bind(&OrderedFunc, &order, 2)); 696 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 697 Bind(&OrderedFunc, &order, 3)); 698 ThreadTaskRunnerHandle::Get()->PostTask( 699 FROM_HERE, Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50))); 700 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 701 Bind(&OrderedFunc, &order, 5)); 702 ThreadTaskRunnerHandle::Get()->PostNonNestableTask( 703 FROM_HERE, Bind(&QuitFunc, &order, 6)); 704 705 RunLoop().Run(); 706 707 // FIFO order. 708 ASSERT_EQ(12U, order.Size()); 709 EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true)); 710 EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true)); 711 EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false)); 712 EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true)); 713 EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false)); 714 EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true)); 715 EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false)); 716 EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false)); 717 EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true)); 718 EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false)); 719 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true)); 720 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false)); 721 } 722 723 void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) { 724 order->RecordStart(RUNS, cookie); 725 { 726 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); 727 run_loop->Run(); 728 } 729 order->RecordEnd(RUNS, cookie); 730 } 731 732 void FuncThatQuitsNow() { 733 MessageLoop::current()->QuitNow(); 734 } 735 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. 736 void RunTest_QuitNow(MessagePumpFactory factory) { 737 std::unique_ptr<MessagePump> pump(factory()); 738 MessageLoop loop(std::move(pump)); 739 740 TaskList order; 741 742 RunLoop run_loop; 743 744 ThreadTaskRunnerHandle::Get()->PostTask( 745 FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); 746 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 747 Bind(&OrderedFunc, &order, 2)); 748 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&FuncThatQuitsNow)); 749 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 750 Bind(&OrderedFunc, &order, 3)); 751 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&FuncThatQuitsNow)); 752 ThreadTaskRunnerHandle::Get()->PostTask( 753 FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs 754 755 RunLoop().Run(); 756 757 ASSERT_EQ(6U, order.Size()); 758 int task_index = 0; 759 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); 760 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); 761 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); 762 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); 763 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); 764 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); 765 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); 766 } 767 768 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. 769 void RunTest_RunLoopQuitTop(MessagePumpFactory factory) { 770 std::unique_ptr<MessagePump> pump(factory()); 771 MessageLoop loop(std::move(pump)); 772 773 TaskList order; 774 775 RunLoop outer_run_loop; 776 RunLoop nested_run_loop; 777 778 ThreadTaskRunnerHandle::Get()->PostTask( 779 FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); 780 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 781 outer_run_loop.QuitClosure()); 782 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 783 Bind(&OrderedFunc, &order, 2)); 784 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 785 nested_run_loop.QuitClosure()); 786 787 outer_run_loop.Run(); 788 789 ASSERT_EQ(4U, order.Size()); 790 int task_index = 0; 791 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); 792 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); 793 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); 794 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); 795 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); 796 } 797 798 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. 799 void RunTest_RunLoopQuitNested(MessagePumpFactory factory) { 800 std::unique_ptr<MessagePump> pump(factory()); 801 MessageLoop loop(std::move(pump)); 802 803 TaskList order; 804 805 RunLoop outer_run_loop; 806 RunLoop nested_run_loop; 807 808 ThreadTaskRunnerHandle::Get()->PostTask( 809 FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); 810 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 811 nested_run_loop.QuitClosure()); 812 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 813 Bind(&OrderedFunc, &order, 2)); 814 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 815 outer_run_loop.QuitClosure()); 816 817 outer_run_loop.Run(); 818 819 ASSERT_EQ(4U, order.Size()); 820 int task_index = 0; 821 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); 822 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); 823 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); 824 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); 825 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); 826 } 827 828 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. 829 void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) { 830 std::unique_ptr<MessagePump> pump(factory()); 831 MessageLoop loop(std::move(pump)); 832 833 TaskList order; 834 835 RunLoop outer_run_loop; 836 RunLoop nested_run_loop; 837 RunLoop bogus_run_loop; 838 839 ThreadTaskRunnerHandle::Get()->PostTask( 840 FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); 841 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 842 bogus_run_loop.QuitClosure()); 843 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 844 Bind(&OrderedFunc, &order, 2)); 845 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 846 outer_run_loop.QuitClosure()); 847 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 848 nested_run_loop.QuitClosure()); 849 850 outer_run_loop.Run(); 851 852 ASSERT_EQ(4U, order.Size()); 853 int task_index = 0; 854 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); 855 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); 856 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); 857 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); 858 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); 859 } 860 861 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. 862 void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) { 863 std::unique_ptr<MessagePump> pump(factory()); 864 MessageLoop loop(std::move(pump)); 865 866 TaskList order; 867 868 RunLoop outer_run_loop; 869 RunLoop nested_loop1; 870 RunLoop nested_loop2; 871 RunLoop nested_loop3; 872 RunLoop nested_loop4; 873 874 ThreadTaskRunnerHandle::Get()->PostTask( 875 FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1))); 876 ThreadTaskRunnerHandle::Get()->PostTask( 877 FROM_HERE, Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2))); 878 ThreadTaskRunnerHandle::Get()->PostTask( 879 FROM_HERE, Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3))); 880 ThreadTaskRunnerHandle::Get()->PostTask( 881 FROM_HERE, Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4))); 882 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 883 Bind(&OrderedFunc, &order, 5)); 884 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 885 outer_run_loop.QuitClosure()); 886 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 887 Bind(&OrderedFunc, &order, 6)); 888 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 889 nested_loop1.QuitClosure()); 890 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 891 Bind(&OrderedFunc, &order, 7)); 892 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 893 nested_loop2.QuitClosure()); 894 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 895 Bind(&OrderedFunc, &order, 8)); 896 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 897 nested_loop3.QuitClosure()); 898 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 899 Bind(&OrderedFunc, &order, 9)); 900 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 901 nested_loop4.QuitClosure()); 902 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 903 Bind(&OrderedFunc, &order, 10)); 904 905 outer_run_loop.Run(); 906 907 ASSERT_EQ(18U, order.Size()); 908 int task_index = 0; 909 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); 910 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true)); 911 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true)); 912 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true)); 913 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true)); 914 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false)); 915 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true)); 916 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false)); 917 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true)); 918 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false)); 919 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true)); 920 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false)); 921 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true)); 922 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false)); 923 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false)); 924 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false)); 925 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false)); 926 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); 927 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); 928 } 929 930 // Tests RunLoopQuit works before RunWithID. 931 void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) { 932 std::unique_ptr<MessagePump> pump(factory()); 933 MessageLoop loop(std::move(pump)); 934 935 TaskList order; 936 937 RunLoop run_loop; 938 939 run_loop.Quit(); 940 941 ThreadTaskRunnerHandle::Get()->PostTask( 942 FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs 943 ThreadTaskRunnerHandle::Get()->PostTask( 944 FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs 945 946 run_loop.Run(); 947 948 ASSERT_EQ(0U, order.Size()); 949 } 950 951 // Tests RunLoopQuit works during RunWithID. 952 void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) { 953 std::unique_ptr<MessagePump> pump(factory()); 954 MessageLoop loop(std::move(pump)); 955 956 TaskList order; 957 958 RunLoop run_loop; 959 960 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 961 Bind(&OrderedFunc, &order, 1)); 962 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop.QuitClosure()); 963 ThreadTaskRunnerHandle::Get()->PostTask( 964 FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs 965 ThreadTaskRunnerHandle::Get()->PostTask( 966 FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs 967 968 run_loop.Run(); 969 970 ASSERT_EQ(2U, order.Size()); 971 int task_index = 0; 972 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true)); 973 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false)); 974 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); 975 } 976 977 // Tests RunLoopQuit works after RunWithID. 978 void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) { 979 std::unique_ptr<MessagePump> pump(factory()); 980 MessageLoop loop(std::move(pump)); 981 982 TaskList order; 983 984 RunLoop run_loop; 985 986 ThreadTaskRunnerHandle::Get()->PostTask( 987 FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); 988 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 989 Bind(&OrderedFunc, &order, 2)); 990 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&FuncThatQuitsNow)); 991 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 992 Bind(&OrderedFunc, &order, 3)); 993 ThreadTaskRunnerHandle::Get()->PostTask( 994 FROM_HERE, run_loop.QuitClosure()); // has no affect 995 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, 996 Bind(&OrderedFunc, &order, 4)); 997 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&FuncThatQuitsNow)); 998 999 RunLoop outer_run_loop; 1000 outer_run_loop.Run(); 1001 1002 ASSERT_EQ(8U, order.Size()); 1003 int task_index = 0; 1004 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); 1005 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); 1006 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); 1007 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); 1008 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); 1009 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); 1010 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true)); 1011 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false)); 1012 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); 1013 } 1014 1015 void PostNTasksThenQuit(int posts_remaining) { 1016 if (posts_remaining > 1) { 1017 ThreadTaskRunnerHandle::Get()->PostTask( 1018 FROM_HERE, Bind(&PostNTasksThenQuit, posts_remaining - 1)); 1019 } else { 1020 MessageLoop::current()->QuitWhenIdle(); 1021 } 1022 } 1023 1024 // There was a bug in the MessagePumpGLib where posting tasks recursively 1025 // caused the message loop to hang, due to the buffer of the internal pipe 1026 // becoming full. Test all MessageLoop types to ensure this issue does not 1027 // exist in other MessagePumps. 1028 // 1029 // On Linux, the pipe buffer size is 64KiB by default. The bug caused one 1030 // byte accumulated in the pipe per two posts, so we should repeat 128K 1031 // times to reproduce the bug. 1032 void RunTest_RecursivePosts(MessagePumpFactory factory) { 1033 const int kNumTimes = 1 << 17; 1034 std::unique_ptr<MessagePump> pump(factory()); 1035 MessageLoop loop(std::move(pump)); 1036 loop.task_runner()->PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes)); 1037 RunLoop().Run(); 1038 } 1039 1040 } // namespace test 1041 } // namespace base 1042