| Index: base/threading/sequenced_worker_pool_unittest.cc
|
| diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
|
| index 3f55152779aaf3ca00f3f251c004d5cb9da902ad..b95830f70d35dfd4ea7feaad976b741352280501 100644
|
| --- a/base/threading/sequenced_worker_pool_unittest.cc
|
| +++ b/base/threading/sequenced_worker_pool_unittest.cc
|
| @@ -5,7 +5,11 @@
|
| #include <algorithm>
|
|
|
| #include "base/bind.h"
|
| +#include "base/compiler_specific.h"
|
| #include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/message_loop_proxy.h"
|
| #include "base/synchronization/condition_variable.h"
|
| #include "base/synchronization/lock.h"
|
| #include "base/task_runner_test_template.h"
|
| @@ -141,26 +145,81 @@ class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
|
| size_t started_events_;
|
| };
|
|
|
| -class SequencedWorkerPoolTest : public testing::Test,
|
| - public SequencedWorkerPool::TestingObserver {
|
| +// Wrapper around SequencedWorkerPool that blocks destruction until
|
| +// the pool is actually destroyed. This is so that a
|
| +// SequencedWorkerPool from one test doesn't outlive its test and
|
| +// cause strange races with other tests that touch global stuff (like
|
| +// histograms and logging). However, this requires that nothing else
|
| +// on this thread holds a ref to the pool when the
|
| +// SequencedWorkerPoolOwner is destroyed.
|
| +class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver {
|
| public:
|
| - SequencedWorkerPoolTest()
|
| - : pool_(new SequencedWorkerPool(kNumWorkerThreads, "test")),
|
| - tracker_(new TestTracker) {
|
| + SequencedWorkerPoolOwner(size_t max_threads,
|
| + const std::string& thread_name_prefix)
|
| + : constructor_message_loop_(MessageLoop::current()),
|
| + pool_(new SequencedWorkerPool(max_threads, thread_name_prefix)) {
|
| pool_->SetTestingObserver(this);
|
| }
|
| - ~SequencedWorkerPoolTest() {
|
| +
|
| + virtual ~SequencedWorkerPoolOwner() {
|
| + pool_ = NULL;
|
| + MessageLoop::current()->Run();
|
| + }
|
| +
|
| + // Don't change the return pool's testing observer.
|
| + const scoped_refptr<SequencedWorkerPool>& pool() {
|
| + return pool_;
|
| + }
|
| +
|
| + // The given callback will be called on WillWaitForShutdown().
|
| + void SetWillWaitForShutdownCallback(const Closure& callback) {
|
| + will_wait_for_shutdown_callback_ = callback;
|
| + }
|
| +
|
| + private:
|
| + // SequencedWorkerPool::TestingObserver implementation.
|
| + virtual void WillWaitForShutdown() OVERRIDE {
|
| + if (!will_wait_for_shutdown_callback_.is_null()) {
|
| + will_wait_for_shutdown_callback_.Run();
|
| + }
|
| }
|
|
|
| - virtual void SetUp() {
|
| + virtual void OnDestruct() OVERRIDE {
|
| + constructor_message_loop_->PostTask(
|
| + FROM_HERE,
|
| + constructor_message_loop_->QuitClosure());
|
| }
|
| +
|
| + MessageLoop* const constructor_message_loop_;
|
| + scoped_refptr<SequencedWorkerPool> pool_;
|
| + Closure will_wait_for_shutdown_callback_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolOwner);
|
| +};
|
| +
|
| +class SequencedWorkerPoolTest : public testing::Test {
|
| + public:
|
| + SequencedWorkerPoolTest()
|
| + : pool_owner_(kNumWorkerThreads, "test"),
|
| + tracker_(new TestTracker) {}
|
| +
|
| + ~SequencedWorkerPoolTest() {}
|
| +
|
| + virtual void SetUp() {}
|
| +
|
| virtual void TearDown() {
|
| - pool_->Shutdown();
|
| + pool()->Shutdown();
|
| }
|
|
|
| - const scoped_refptr<SequencedWorkerPool>& pool() { return pool_; }
|
| + const scoped_refptr<SequencedWorkerPool>& pool() {
|
| + return pool_owner_.pool();
|
| + }
|
| TestTracker* tracker() { return tracker_.get(); }
|
|
|
| + void SetWillWaitForShutdownCallback(const Closure& callback) {
|
| + pool_owner_.SetWillWaitForShutdownCallback(callback);
|
| + }
|
| +
|
| // Ensures that the given number of worker threads is created by adding
|
| // tasks and waiting until they complete. Worker thread creation is
|
| // serialized, can happen on background threads asynchronously, and doesn't
|
| @@ -194,18 +253,9 @@ class SequencedWorkerPoolTest : public testing::Test,
|
| tracker()->ClearCompleteSequence();
|
| }
|
|
|
| - protected:
|
| - // This closure will be executed right before the pool blocks on shutdown.
|
| - base::Closure before_wait_for_shutdown_;
|
| -
|
| private:
|
| - // SequencedWorkerPool::TestingObserver implementation.
|
| - virtual void WillWaitForShutdown() {
|
| - if (!before_wait_for_shutdown_.is_null())
|
| - before_wait_for_shutdown_.Run();
|
| - }
|
| -
|
| - const scoped_refptr<SequencedWorkerPool> pool_;
|
| + MessageLoop message_loop_;
|
| + SequencedWorkerPoolOwner pool_owner_;
|
| const scoped_refptr<TestTracker> tracker_;
|
| };
|
|
|
| @@ -272,26 +322,27 @@ TEST_F(SequencedWorkerPoolTest, LotsOfTasks) {
|
| // This test is meant to shake out any concurrency issues between
|
| // pools (like histograms).
|
| TEST_F(SequencedWorkerPoolTest, LotsOfTasksTwoPools) {
|
| - scoped_refptr<SequencedWorkerPool> pool1(
|
| - new SequencedWorkerPool(kNumWorkerThreads, "test1"));
|
| - scoped_refptr<SequencedWorkerPool> pool2(
|
| - new SequencedWorkerPool(kNumWorkerThreads, "test2"));
|
| + SequencedWorkerPoolOwner pool1(kNumWorkerThreads, "test1");
|
| + SequencedWorkerPoolOwner pool2(kNumWorkerThreads, "test2");
|
|
|
| base::Closure slow_task = base::Bind(&TestTracker::SlowTask, tracker(), 0);
|
| - pool1->PostWorkerTask(FROM_HERE, slow_task);
|
| - pool2->PostWorkerTask(FROM_HERE, slow_task);
|
| + pool1.pool()->PostWorkerTask(FROM_HERE, slow_task);
|
| + pool2.pool()->PostWorkerTask(FROM_HERE, slow_task);
|
|
|
| const size_t kNumTasks = 20;
|
| for (size_t i = 1; i < kNumTasks; i++) {
|
| base::Closure fast_task =
|
| base::Bind(&TestTracker::FastTask, tracker(), i);
|
| - pool1->PostWorkerTask(FROM_HERE, fast_task);
|
| - pool2->PostWorkerTask(FROM_HERE, fast_task);
|
| + pool1.pool()->PostWorkerTask(FROM_HERE, fast_task);
|
| + pool2.pool()->PostWorkerTask(FROM_HERE, fast_task);
|
| }
|
|
|
| std::vector<int> result =
|
| tracker()->WaitUntilTasksComplete(2*kNumTasks);
|
| EXPECT_EQ(2*kNumTasks, result.size());
|
| +
|
| + pool2.pool()->Shutdown();
|
| + pool1.pool()->Shutdown();
|
| }
|
|
|
| // Test that tasks with the same sequence token are executed in order but don't
|
| @@ -383,10 +434,10 @@ TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) {
|
| SequencedWorkerPool::BLOCK_SHUTDOWN);
|
|
|
| // Shutdown the worker pool. This should discard all non-blocking tasks.
|
| - before_wait_for_shutdown_ =
|
| + SetWillWaitForShutdownCallback(
|
| base::Bind(&EnsureTasksToCompleteCountAndUnblock,
|
| scoped_refptr<TestTracker>(tracker()), 0,
|
| - &blocker, kNumWorkerThreads);
|
| + &blocker, kNumWorkerThreads));
|
| pool()->Shutdown();
|
|
|
| std::vector<int> result = tracker()->WaitUntilTasksComplete(4);
|
| @@ -436,17 +487,18 @@ class SequencedWorkerPoolTaskRunnerTestDelegate {
|
| ~SequencedWorkerPoolTaskRunnerTestDelegate() {}
|
|
|
| void StartTaskRunner() {
|
| - worker_pool_ =
|
| - new SequencedWorkerPool(10, "SequencedWorkerPoolTaskRunnerTest");
|
| + pool_owner_.reset(
|
| + new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest"));
|
| }
|
|
|
| scoped_refptr<SequencedWorkerPool> GetTaskRunner() {
|
| - return worker_pool_;
|
| + return pool_owner_->pool();
|
| }
|
|
|
| void StopTaskRunner() {
|
| - worker_pool_->Shutdown();
|
| - worker_pool_ = NULL;
|
| + pool_owner_->pool()->Shutdown();
|
| + // Don't reset |pool_owner_| here, as the test may still hold a
|
| + // reference to the pool.
|
| }
|
|
|
| bool TaskRunnerHandlesNonZeroDelays() const {
|
| @@ -456,7 +508,8 @@ class SequencedWorkerPoolTaskRunnerTestDelegate {
|
| }
|
|
|
| private:
|
| - scoped_refptr<SequencedWorkerPool> worker_pool_;
|
| + MessageLoop message_loop_;
|
| + scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
|
| };
|
|
|
| INSTANTIATE_TYPED_TEST_CASE_P(
|
|
|