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 |