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