| 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 ed5f89694983ca707b977990a59982ca5a9fb83b..9d0f607775d47e4023bc0918f0f125dca61dc816 100644
|
| --- a/base/threading/sequenced_worker_pool_unittest.cc
|
| +++ b/base/threading/sequenced_worker_pool_unittest.cc
|
| @@ -67,6 +67,23 @@ class ThreadBlocker {
|
| size_t unblock_counter_;
|
| };
|
|
|
| +class DestructionDeadlockChecker
|
| + : public base::RefCountedThreadSafe<DestructionDeadlockChecker> {
|
| + public:
|
| + DestructionDeadlockChecker(const scoped_refptr<SequencedWorkerPool>& pool)
|
| + : pool_(pool) {}
|
| +
|
| + protected:
|
| + virtual ~DestructionDeadlockChecker() {
|
| + // This method should not deadlock.
|
| + pool_->RunsTasksOnCurrentThread();
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<SequencedWorkerPool> pool_;
|
| + friend class base::RefCountedThreadSafe<DestructionDeadlockChecker>;
|
| +};
|
| +
|
| class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
|
| public:
|
| TestTracker()
|
| @@ -117,6 +134,20 @@ class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
|
| SignalWorkerDone(id);
|
| }
|
|
|
| + // This task posts itself back onto the SequencedWorkerPool before it
|
| + // finishes running. Each instance of the task maintains a strong reference
|
| + // to a DestructionDeadlockChecker. The DestructionDeadlockChecker is only
|
| + // destroyed when the task is destroyed without being run, which only happens
|
| + // during destruction of the SequencedWorkerPool.
|
| + void PostRepostingTask(
|
| + const scoped_refptr<SequencedWorkerPool>& pool,
|
| + const scoped_refptr<DestructionDeadlockChecker>& checker) {
|
| + Closure reposting_task =
|
| + base::Bind(&TestTracker::PostRepostingTask, this, pool, checker);
|
| + pool->PostWorkerTaskWithShutdownBehavior(
|
| + FROM_HERE, reposting_task, SequencedWorkerPool::SKIP_ON_SHUTDOWN);
|
| + }
|
| +
|
| // Waits until the given number of tasks have started executing.
|
| void WaitUntilTasksBlocked(size_t count) {
|
| {
|
| @@ -749,6 +780,21 @@ TEST_F(SequencedWorkerPoolTest, IsRunningOnCurrentThread) {
|
| unused_pool->Shutdown();
|
| }
|
|
|
| +// Checks that tasks are destroyed in the right context during shutdown. If a
|
| +// task is destroyed while SequencedWorkerPool's global lock is held,
|
| +// SequencedWorkerPool might deadlock.
|
| +TEST_F(SequencedWorkerPoolTest, AvoidsDeadlockOnShutdown) {
|
| + for (int i = 0; i < 4; ++i) {
|
| + scoped_refptr<DestructionDeadlockChecker> checker(
|
| + new DestructionDeadlockChecker(pool()));
|
| + tracker()->PostRepostingTask(pool(), checker);
|
| + }
|
| +
|
| + // Shutting down the pool should destroy the DestructionDeadlockCheckers,
|
| + // which in turn should not deadlock in their destructors.
|
| + pool()->Shutdown();
|
| +}
|
| +
|
| // Verify that FlushForTesting works as intended.
|
| TEST_F(SequencedWorkerPoolTest, FlushForTesting) {
|
| // Should be fine to call on a new instance.
|
|
|