| 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 cond_var_.Signal(); | 60 cond_var_.Signal(); |
| 61 } | 61 } |
| 62 | 62 |
| 63 private: | 63 private: |
| 64 base::Lock lock_; | 64 base::Lock lock_; |
| 65 base::ConditionVariable cond_var_; | 65 base::ConditionVariable cond_var_; |
| 66 | 66 |
| 67 size_t unblock_counter_; | 67 size_t unblock_counter_; |
| 68 }; | 68 }; |
| 69 | 69 |
| 70 class DestructionDeadlockChecker |
| 71 : public base::RefCountedThreadSafe<DestructionDeadlockChecker> { |
| 72 public: |
| 73 DestructionDeadlockChecker(const scoped_refptr<SequencedWorkerPool>& pool) |
| 74 : pool_(pool) {} |
| 75 |
| 76 protected: |
| 77 virtual ~DestructionDeadlockChecker() { |
| 78 // This method should not deadlock. |
| 79 pool_->RunsTasksOnCurrentThread(); |
| 80 } |
| 81 |
| 82 private: |
| 83 scoped_refptr<SequencedWorkerPool> pool_; |
| 84 friend class base::RefCountedThreadSafe<DestructionDeadlockChecker>; |
| 85 }; |
| 86 |
| 70 class TestTracker : public base::RefCountedThreadSafe<TestTracker> { | 87 class TestTracker : public base::RefCountedThreadSafe<TestTracker> { |
| 71 public: | 88 public: |
| 72 TestTracker() | 89 TestTracker() |
| 73 : lock_(), | 90 : lock_(), |
| 74 cond_var_(&lock_), | 91 cond_var_(&lock_), |
| 75 started_events_(0) { | 92 started_events_(0) { |
| 76 } | 93 } |
| 77 | 94 |
| 78 // Each of these tasks appends the argument to the complete sequence vector | 95 // Each of these tasks appends the argument to the complete sequence vector |
| 79 // so calling code can see what order they finished in. | 96 // so calling code can see what order they finished in. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 110 EXPECT_EQ(expected_return_value, | 127 EXPECT_EQ(expected_return_value, |
| 111 pool->PostWorkerTaskWithShutdownBehavior( | 128 pool->PostWorkerTaskWithShutdownBehavior( |
| 112 FROM_HERE, fast_task, | 129 FROM_HERE, fast_task, |
| 113 SequencedWorkerPool::SKIP_ON_SHUTDOWN)); | 130 SequencedWorkerPool::SKIP_ON_SHUTDOWN)); |
| 114 pool->PostWorkerTaskWithShutdownBehavior( | 131 pool->PostWorkerTaskWithShutdownBehavior( |
| 115 FROM_HERE, fast_task, | 132 FROM_HERE, fast_task, |
| 116 SequencedWorkerPool::BLOCK_SHUTDOWN); | 133 SequencedWorkerPool::BLOCK_SHUTDOWN); |
| 117 SignalWorkerDone(id); | 134 SignalWorkerDone(id); |
| 118 } | 135 } |
| 119 | 136 |
| 137 // This task posts itself back onto the SequencedWorkerPool before it |
| 138 // finishes running. Each instance of the task maintains a strong reference |
| 139 // to a DestructionDeadlockChecker. The DestructionDeadlockChecker is only |
| 140 // destroyed when the task is destroyed without being run, which only happens |
| 141 // during destruction of the SequencedWorkerPool. |
| 142 void PostRepostingTask( |
| 143 const scoped_refptr<SequencedWorkerPool>& pool, |
| 144 const scoped_refptr<DestructionDeadlockChecker>& checker) { |
| 145 Closure reposting_task = |
| 146 base::Bind(&TestTracker::PostRepostingTask, this, pool, checker); |
| 147 pool->PostWorkerTaskWithShutdownBehavior( |
| 148 FROM_HERE, reposting_task, SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| 149 } |
| 150 |
| 120 // Waits until the given number of tasks have started executing. | 151 // Waits until the given number of tasks have started executing. |
| 121 void WaitUntilTasksBlocked(size_t count) { | 152 void WaitUntilTasksBlocked(size_t count) { |
| 122 { | 153 { |
| 123 base::AutoLock lock(lock_); | 154 base::AutoLock lock(lock_); |
| 124 while (started_events_ < count) | 155 while (started_events_ < count) |
| 125 cond_var_.Wait(); | 156 cond_var_.Wait(); |
| 126 } | 157 } |
| 127 cond_var_.Signal(); | 158 cond_var_.Signal(); |
| 128 } | 159 } |
| 129 | 160 |
| (...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 base::Bind(&IsRunningOnCurrentThreadTask, | 773 base::Bind(&IsRunningOnCurrentThreadTask, |
| 743 token2, unsequenced_token, pool(), unused_pool)); | 774 token2, unsequenced_token, pool(), unused_pool)); |
| 744 pool()->PostWorkerTask( | 775 pool()->PostWorkerTask( |
| 745 FROM_HERE, | 776 FROM_HERE, |
| 746 base::Bind(&IsRunningOnCurrentThreadTask, | 777 base::Bind(&IsRunningOnCurrentThreadTask, |
| 747 unsequenced_token, token1, pool(), unused_pool)); | 778 unsequenced_token, token1, pool(), unused_pool)); |
| 748 pool()->Shutdown(); | 779 pool()->Shutdown(); |
| 749 unused_pool->Shutdown(); | 780 unused_pool->Shutdown(); |
| 750 } | 781 } |
| 751 | 782 |
| 783 // Checks that tasks are destroyed in the right context during shutdown. If a |
| 784 // task is destroyed while SequencedWorkerPool's global lock is held, |
| 785 // SequencedWorkerPool might deadlock. |
| 786 TEST_F(SequencedWorkerPoolTest, AvoidsDeadlockOnShutdown) { |
| 787 for (int i = 0; i < 4; ++i) { |
| 788 scoped_refptr<DestructionDeadlockChecker> checker( |
| 789 new DestructionDeadlockChecker(pool())); |
| 790 tracker()->PostRepostingTask(pool(), checker); |
| 791 } |
| 792 |
| 793 // Shutting down the pool should destroy the DestructionDeadlockCheckers, |
| 794 // which in turn should not deadlock in their destructors. |
| 795 pool()->Shutdown(); |
| 796 } |
| 797 |
| 752 // Verify that FlushForTesting works as intended. | 798 // Verify that FlushForTesting works as intended. |
| 753 TEST_F(SequencedWorkerPoolTest, FlushForTesting) { | 799 TEST_F(SequencedWorkerPoolTest, FlushForTesting) { |
| 754 // Should be fine to call on a new instance. | 800 // Should be fine to call on a new instance. |
| 755 pool()->FlushForTesting(); | 801 pool()->FlushForTesting(); |
| 756 | 802 |
| 757 // Queue up a bunch of work, including a long delayed task and | 803 // Queue up a bunch of work, including a long delayed task and |
| 758 // a task that produces additional tasks as an artifact. | 804 // a task that produces additional tasks as an artifact. |
| 759 pool()->PostDelayedWorkerTask( | 805 pool()->PostDelayedWorkerTask( |
| 760 FROM_HERE, | 806 FROM_HERE, |
| 761 base::Bind(&TestTracker::FastTask, tracker(), 0), | 807 base::Bind(&TestTracker::FastTask, tracker(), 0), |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 909 SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest, | 955 SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest, |
| 910 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); | 956 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); |
| 911 | 957 |
| 912 INSTANTIATE_TYPED_TEST_CASE_P( | 958 INSTANTIATE_TYPED_TEST_CASE_P( |
| 913 SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest, | 959 SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest, |
| 914 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); | 960 SequencedWorkerPoolSequencedTaskRunnerTestDelegate); |
| 915 | 961 |
| 916 } // namespace | 962 } // namespace |
| 917 | 963 |
| 918 } // namespace base | 964 } // namespace base |
| OLD | NEW |