| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/threading/sequenced_worker_pool.h" | 5 #include "base/threading/sequenced_worker_pool.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 const size_t kNumTasks = 20; | 291 const size_t kNumTasks = 20; |
| 292 for (size_t i = 1; i < kNumTasks; i++) { | 292 for (size_t i = 1; i < kNumTasks; i++) { |
| 293 base::Closure fast_task = | 293 base::Closure fast_task = |
| 294 base::Bind(&TestTracker::FastTask, tracker(), i); | 294 base::Bind(&TestTracker::FastTask, tracker(), i); |
| 295 pool1.pool()->PostWorkerTask(FROM_HERE, fast_task); | 295 pool1.pool()->PostWorkerTask(FROM_HERE, fast_task); |
| 296 pool2.pool()->PostWorkerTask(FROM_HERE, fast_task); | 296 pool2.pool()->PostWorkerTask(FROM_HERE, fast_task); |
| 297 } | 297 } |
| 298 | 298 |
| 299 std::vector<int> result = | 299 std::vector<int> result = |
| 300 tracker()->WaitUntilTasksComplete(2*kNumTasks); | 300 tracker()->WaitUntilTasksComplete(2*kNumTasks); |
| 301 EXPECT_EQ(2*kNumTasks, result.size()); | 301 EXPECT_EQ(2 * kNumTasks, result.size()); |
| 302 | 302 |
| 303 pool2.pool()->Shutdown(); | 303 pool2.pool()->Shutdown(); |
| 304 pool1.pool()->Shutdown(); | 304 pool1.pool()->Shutdown(); |
| 305 } | 305 } |
| 306 | 306 |
| 307 // Test that tasks with the same sequence token are executed in order but don't | 307 // Test that tasks with the same sequence token are executed in order but don't |
| 308 // affect other tasks. | 308 // affect other tasks. |
| 309 TEST_F(SequencedWorkerPoolTest, Sequence) { | 309 TEST_F(SequencedWorkerPoolTest, Sequence) { |
| 310 // Fill all the worker threads except one. | 310 // Fill all the worker threads except one. |
| 311 const size_t kNumBackgroundTasks = kNumWorkerThreads - 1; | 311 const size_t kNumBackgroundTasks = kNumWorkerThreads - 1; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 2).size()); | 358 tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 2).size()); |
| 359 | 359 |
| 360 // Allow the first task of token1 to complete. This should run the second. | 360 // Allow the first task of token1 to complete. This should run the second. |
| 361 blocker.Unblock(1); | 361 blocker.Unblock(1); |
| 362 result = tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 4); | 362 result = tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 4); |
| 363 ASSERT_EQ(kNumBackgroundTasks + 4, result.size()); | 363 ASSERT_EQ(kNumBackgroundTasks + 4, result.size()); |
| 364 EXPECT_EQ(100, result[result.size() - 2]); | 364 EXPECT_EQ(100, result[result.size() - 2]); |
| 365 EXPECT_EQ(101, result[result.size() - 1]); | 365 EXPECT_EQ(101, result[result.size() - 1]); |
| 366 } | 366 } |
| 367 | 367 |
| 368 // Tests that any tasks posted after Shutdown are ignored. |
| 369 TEST_F(SequencedWorkerPoolTest, IgnoresAfterShutdown) { |
| 370 // Start tasks to take all the threads and block them. |
| 371 EnsureAllWorkersCreated(); |
| 372 ThreadBlocker blocker; |
| 373 for (size_t i = 0; i < kNumWorkerThreads; i++) { |
| 374 pool()->PostWorkerTask(FROM_HERE, |
| 375 base::Bind(&TestTracker::BlockTask, |
| 376 tracker(), i, &blocker)); |
| 377 } |
| 378 tracker()->WaitUntilTasksBlocked(kNumWorkerThreads); |
| 379 |
| 380 // Shutdown the worker pool. This should discard all non-blocking tasks. |
| 381 SetWillWaitForShutdownCallback( |
| 382 base::Bind(&EnsureTasksToCompleteCountAndUnblock, |
| 383 scoped_refptr<TestTracker>(tracker()), 0, |
| 384 &blocker, kNumWorkerThreads)); |
| 385 pool()->Shutdown(); |
| 386 |
| 387 int old_has_work_call_count = has_work_call_count(); |
| 388 |
| 389 std::vector<int> result = |
| 390 tracker()->WaitUntilTasksComplete(kNumWorkerThreads); |
| 391 |
| 392 // The kNumWorkerThread items should have completed, in no particular |
| 393 // order. |
| 394 ASSERT_EQ(kNumWorkerThreads, result.size()); |
| 395 for (size_t i = 0; i < kNumWorkerThreads; i++) { |
| 396 EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) != |
| 397 result.end()); |
| 398 } |
| 399 |
| 400 // No further tasks, regardless of shutdown mode, should be allowed. |
| 401 EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior( |
| 402 FROM_HERE, |
| 403 base::Bind(&TestTracker::FastTask, tracker(), 100), |
| 404 SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)); |
| 405 EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior( |
| 406 FROM_HERE, |
| 407 base::Bind(&TestTracker::FastTask, tracker(), 101), |
| 408 SequencedWorkerPool::SKIP_ON_SHUTDOWN)); |
| 409 EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior( |
| 410 FROM_HERE, |
| 411 base::Bind(&TestTracker::FastTask, tracker(), 102), |
| 412 SequencedWorkerPool::BLOCK_SHUTDOWN)); |
| 413 |
| 414 ASSERT_EQ(old_has_work_call_count, has_work_call_count()); |
| 415 } |
| 416 |
| 368 // Tests that unrun tasks are discarded properly according to their shutdown | 417 // Tests that unrun tasks are discarded properly according to their shutdown |
| 369 // mode. | 418 // mode. |
| 370 TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) { | 419 TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) { |
| 371 // Start tasks to take all the threads and block them. | 420 // Start tasks to take all the threads and block them. |
| 372 EnsureAllWorkersCreated(); | 421 EnsureAllWorkersCreated(); |
| 373 ThreadBlocker blocker; | 422 ThreadBlocker blocker; |
| 374 for (size_t i = 0; i < kNumWorkerThreads; i++) { | 423 for (size_t i = 0; i < kNumWorkerThreads; i++) { |
| 375 pool()->PostWorkerTask(FROM_HERE, | 424 pool()->PostWorkerTask(FROM_HERE, |
| 376 base::Bind(&TestTracker::BlockTask, | 425 base::Bind(&TestTracker::BlockTask, |
| 377 tracker(), i, &blocker)); | 426 tracker(), i, &blocker)); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 392 base::Bind(&TestTracker::FastTask, tracker(), 102), | 441 base::Bind(&TestTracker::FastTask, tracker(), 102), |
| 393 SequencedWorkerPool::BLOCK_SHUTDOWN); | 442 SequencedWorkerPool::BLOCK_SHUTDOWN); |
| 394 | 443 |
| 395 // Shutdown the worker pool. This should discard all non-blocking tasks. | 444 // Shutdown the worker pool. This should discard all non-blocking tasks. |
| 396 SetWillWaitForShutdownCallback( | 445 SetWillWaitForShutdownCallback( |
| 397 base::Bind(&EnsureTasksToCompleteCountAndUnblock, | 446 base::Bind(&EnsureTasksToCompleteCountAndUnblock, |
| 398 scoped_refptr<TestTracker>(tracker()), 0, | 447 scoped_refptr<TestTracker>(tracker()), 0, |
| 399 &blocker, kNumWorkerThreads)); | 448 &blocker, kNumWorkerThreads)); |
| 400 pool()->Shutdown(); | 449 pool()->Shutdown(); |
| 401 | 450 |
| 402 std::vector<int> result = tracker()->WaitUntilTasksComplete(4); | 451 std::vector<int> result = |
| 452 tracker()->WaitUntilTasksComplete(kNumWorkerThreads + 1); |
| 403 | 453 |
| 404 // The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN | 454 // The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN |
| 405 // one, in no particular order. | 455 // one, in no particular order. |
| 406 ASSERT_EQ(4u, result.size()); | 456 ASSERT_EQ(kNumWorkerThreads + 1, result.size()); |
| 407 for (size_t i = 0; i < kNumWorkerThreads; i++) { | 457 for (size_t i = 0; i < kNumWorkerThreads; i++) { |
| 408 EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) != | 458 EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) != |
| 409 result.end()); | 459 result.end()); |
| 410 } | 460 } |
| 411 EXPECT_TRUE(std::find(result.begin(), result.end(), 102) != result.end()); | 461 EXPECT_TRUE(std::find(result.begin(), result.end(), 102) != result.end()); |
| 412 } | 462 } |
| 413 | 463 |
| 414 // Tests that CONTINUE_ON_SHUTDOWN tasks don't block shutdown. | 464 // Tests that CONTINUE_ON_SHUTDOWN tasks don't block shutdown. |
| 415 TEST_F(SequencedWorkerPoolTest, ContinueOnShutdown) { | 465 TEST_F(SequencedWorkerPoolTest, ContinueOnShutdown) { |
| 416 scoped_refptr<TaskRunner> runner(pool()->GetTaskRunnerWithShutdownBehavior( | 466 scoped_refptr<TaskRunner> runner(pool()->GetTaskRunnerWithShutdownBehavior( |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0))); | 501 FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0))); |
| 452 EXPECT_FALSE(sequenced_runner->PostTask( | 502 EXPECT_FALSE(sequenced_runner->PostTask( |
| 453 FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0))); | 503 FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0))); |
| 454 | 504 |
| 455 // Continue the background thread and make sure the tasks can complete. | 505 // Continue the background thread and make sure the tasks can complete. |
| 456 blocker.Unblock(3); | 506 blocker.Unblock(3); |
| 457 std::vector<int> result = tracker()->WaitUntilTasksComplete(3); | 507 std::vector<int> result = tracker()->WaitUntilTasksComplete(3); |
| 458 EXPECT_EQ(3u, result.size()); | 508 EXPECT_EQ(3u, result.size()); |
| 459 } | 509 } |
| 460 | 510 |
| 511 // Tests that SKIP_ON_SHUTDOWN tasks that have been started block Shutdown |
| 512 // until they stop, but tasks not yet started do not. |
| 513 TEST_F(SequencedWorkerPoolTest, SkipOnShutdown) { |
| 514 // Start tasks to take all the threads and block them. |
| 515 EnsureAllWorkersCreated(); |
| 516 ThreadBlocker blocker; |
| 517 |
| 518 // Now block all the threads with SKIP_ON_SHUTDOWN. Shutdown() should not |
| 519 // return until these tasks have completed. |
| 520 for (size_t i = 0; i < kNumWorkerThreads; i++) { |
| 521 pool()->PostWorkerTaskWithShutdownBehavior( |
| 522 FROM_HERE, |
| 523 base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker), |
| 524 SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| 525 } |
| 526 tracker()->WaitUntilTasksBlocked(kNumWorkerThreads); |
| 527 |
| 528 // Now post an additional task as SKIP_ON_SHUTDOWN, which should not be |
| 529 // executed once Shutdown() has been called. |
| 530 pool()->PostWorkerTaskWithShutdownBehavior( |
| 531 FROM_HERE, |
| 532 base::Bind(&TestTracker::BlockTask, |
| 533 tracker(), 0, &blocker), |
| 534 SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| 535 |
| 536 // This callback will only be invoked if SKIP_ON_SHUTDOWN tasks that have |
| 537 // been started block shutdown. |
| 538 SetWillWaitForShutdownCallback( |
| 539 base::Bind(&EnsureTasksToCompleteCountAndUnblock, |
| 540 scoped_refptr<TestTracker>(tracker()), 0, |
| 541 &blocker, kNumWorkerThreads)); |
| 542 |
| 543 // No tasks should have completed yet. |
| 544 EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size()); |
| 545 |
| 546 // This should not block. If this test hangs, it means it failed. |
| 547 pool()->Shutdown(); |
| 548 |
| 549 // Shutdown should not return until all of the tasks have completed. |
| 550 std::vector<int> result = |
| 551 tracker()->WaitUntilTasksComplete(kNumWorkerThreads); |
| 552 |
| 553 // Only tasks marked SKIP_ON_SHUTDOWN that were already started should be |
| 554 // allowed to complete. No additional non-blocking tasks should have been |
| 555 // started. |
| 556 ASSERT_EQ(kNumWorkerThreads, result.size()); |
| 557 for (size_t i = 0; i < kNumWorkerThreads; i++) { |
| 558 EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) != |
| 559 result.end()); |
| 560 } |
| 561 } |
| 562 |
| 461 // Ensure all worker threads are created, and then trigger a spurious | 563 // Ensure all worker threads are created, and then trigger a spurious |
| 462 // work signal. This shouldn't cause any other work signals to be | 564 // work signal. This shouldn't cause any other work signals to be |
| 463 // triggered. This is a regression test for http://crbug.com/117469. | 565 // triggered. This is a regression test for http://crbug.com/117469. |
| 464 TEST_F(SequencedWorkerPoolTest, SpuriousWorkSignal) { | 566 TEST_F(SequencedWorkerPoolTest, SpuriousWorkSignal) { |
| 465 EnsureAllWorkersCreated(); | 567 EnsureAllWorkersCreated(); |
| 466 int old_has_work_call_count = has_work_call_count(); | 568 int old_has_work_call_count = has_work_call_count(); |
| 467 pool()->SignalHasWorkForTesting(); | 569 pool()->SignalHasWorkForTesting(); |
| 468 // This is inherently racy, but can only produce false positives. | 570 // This is inherently racy, but can only produce false positives. |
| 469 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); | 571 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); |
| 470 EXPECT_EQ(old_has_work_call_count + 1, has_work_call_count()); | 572 EXPECT_EQ(old_has_work_call_count + 1, has_work_call_count()); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest, | 742 SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest, |
| 641 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); | 743 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); |
| 642 | 744 |
| 643 INSTANTIATE_TYPED_TEST_CASE_P( | 745 INSTANTIATE_TYPED_TEST_CASE_P( |
| 644 SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest, | 746 SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest, |
| 645 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); | 747 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); |
| 646 | 748 |
| 647 } // namespace | 749 } // namespace |
| 648 | 750 |
| 649 } // namespace base | 751 } // namespace base |
| OLD | NEW |