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