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 <algorithm> | 5 #include <algorithm> |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/compiler_specific.h" |
8 #include "base/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
| 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/message_loop.h" |
| 12 #include "base/message_loop_proxy.h" |
9 #include "base/synchronization/condition_variable.h" | 13 #include "base/synchronization/condition_variable.h" |
10 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
11 #include "base/task_runner_test_template.h" | 15 #include "base/task_runner_test_template.h" |
12 #include "base/threading/platform_thread.h" | 16 #include "base/threading/platform_thread.h" |
13 #include "base/threading/sequenced_worker_pool.h" | 17 #include "base/threading/sequenced_worker_pool.h" |
14 #include "base/tracked_objects.h" | 18 #include "base/tracked_objects.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
16 | 20 |
17 namespace base { | 21 namespace base { |
18 | 22 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 | 138 |
135 base::ConditionVariable cond_var_; | 139 base::ConditionVariable cond_var_; |
136 | 140 |
137 // Protected by lock_. | 141 // Protected by lock_. |
138 std::vector<int> complete_sequence_; | 142 std::vector<int> complete_sequence_; |
139 | 143 |
140 // Counter of the number of "block" workers that have started. | 144 // Counter of the number of "block" workers that have started. |
141 size_t started_events_; | 145 size_t started_events_; |
142 }; | 146 }; |
143 | 147 |
144 class SequencedWorkerPoolTest : public testing::Test, | 148 // Wrapper around SequencedWorkerPool that blocks destruction until |
145 public SequencedWorkerPool::TestingObserver { | 149 // the pool is actually destroyed. This is so that a |
| 150 // SequencedWorkerPool from one test doesn't outlive its test and |
| 151 // cause strange races with other tests that touch global stuff (like |
| 152 // histograms and logging). However, this requires that nothing else |
| 153 // on this thread holds a ref to the pool when the |
| 154 // SequencedWorkerPoolOwner is destroyed. |
| 155 class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver { |
| 156 public: |
| 157 SequencedWorkerPoolOwner(size_t max_threads, |
| 158 const std::string& thread_name_prefix) |
| 159 : constructor_message_loop_(MessageLoop::current()), |
| 160 pool_(new SequencedWorkerPool(max_threads, thread_name_prefix)) { |
| 161 pool_->SetTestingObserver(this); |
| 162 } |
| 163 |
| 164 virtual ~SequencedWorkerPoolOwner() { |
| 165 pool_ = NULL; |
| 166 MessageLoop::current()->Run(); |
| 167 } |
| 168 |
| 169 // Don't change the return pool's testing observer. |
| 170 const scoped_refptr<SequencedWorkerPool>& pool() { |
| 171 return pool_; |
| 172 } |
| 173 |
| 174 // The given callback will be called on WillWaitForShutdown(). |
| 175 void SetWillWaitForShutdownCallback(const Closure& callback) { |
| 176 will_wait_for_shutdown_callback_ = callback; |
| 177 } |
| 178 |
| 179 private: |
| 180 // SequencedWorkerPool::TestingObserver implementation. |
| 181 virtual void WillWaitForShutdown() OVERRIDE { |
| 182 if (!will_wait_for_shutdown_callback_.is_null()) { |
| 183 will_wait_for_shutdown_callback_.Run(); |
| 184 } |
| 185 } |
| 186 |
| 187 virtual void OnDestruct() OVERRIDE { |
| 188 constructor_message_loop_->PostTask( |
| 189 FROM_HERE, |
| 190 constructor_message_loop_->QuitClosure()); |
| 191 } |
| 192 |
| 193 MessageLoop* const constructor_message_loop_; |
| 194 scoped_refptr<SequencedWorkerPool> pool_; |
| 195 Closure will_wait_for_shutdown_callback_; |
| 196 |
| 197 DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolOwner); |
| 198 }; |
| 199 |
| 200 class SequencedWorkerPoolTest : public testing::Test { |
146 public: | 201 public: |
147 SequencedWorkerPoolTest() | 202 SequencedWorkerPoolTest() |
148 : pool_(new SequencedWorkerPool(kNumWorkerThreads, "test")), | 203 : pool_owner_(kNumWorkerThreads, "test"), |
149 tracker_(new TestTracker) { | 204 tracker_(new TestTracker) {} |
150 pool_->SetTestingObserver(this); | 205 |
151 } | 206 ~SequencedWorkerPoolTest() {} |
152 ~SequencedWorkerPoolTest() { | 207 |
| 208 virtual void SetUp() {} |
| 209 |
| 210 virtual void TearDown() { |
| 211 pool()->Shutdown(); |
153 } | 212 } |
154 | 213 |
155 virtual void SetUp() { | 214 const scoped_refptr<SequencedWorkerPool>& pool() { |
| 215 return pool_owner_.pool(); |
156 } | 216 } |
157 virtual void TearDown() { | 217 TestTracker* tracker() { return tracker_.get(); } |
158 pool_->Shutdown(); | 218 |
| 219 void SetWillWaitForShutdownCallback(const Closure& callback) { |
| 220 pool_owner_.SetWillWaitForShutdownCallback(callback); |
159 } | 221 } |
160 | 222 |
161 const scoped_refptr<SequencedWorkerPool>& pool() { return pool_; } | |
162 TestTracker* tracker() { return tracker_.get(); } | |
163 | |
164 // Ensures that the given number of worker threads is created by adding | 223 // Ensures that the given number of worker threads is created by adding |
165 // tasks and waiting until they complete. Worker thread creation is | 224 // tasks and waiting until they complete. Worker thread creation is |
166 // serialized, can happen on background threads asynchronously, and doesn't | 225 // serialized, can happen on background threads asynchronously, and doesn't |
167 // happen any more at shutdown. This means that if a test posts a bunch of | 226 // happen any more at shutdown. This means that if a test posts a bunch of |
168 // tasks and calls shutdown, fewer workers will be created than the test may | 227 // tasks and calls shutdown, fewer workers will be created than the test may |
169 // expect. | 228 // expect. |
170 // | 229 // |
171 // This function ensures that this condition can't happen so tests can make | 230 // This function ensures that this condition can't happen so tests can make |
172 // assumptions about the number of workers active. See the comment in | 231 // assumptions about the number of workers active. See the comment in |
173 // PrepareToStartAdditionalThreadIfNecessary in the .cc file for more | 232 // PrepareToStartAdditionalThreadIfNecessary in the .cc file for more |
(...skipping 13 matching lines...) Expand all Loading... |
187 tracker()->WaitUntilTasksBlocked(kNumWorkerThreads); | 246 tracker()->WaitUntilTasksBlocked(kNumWorkerThreads); |
188 | 247 |
189 // Now wake them up and wait until they're done. | 248 // Now wake them up and wait until they're done. |
190 blocker.Unblock(kNumWorkerThreads); | 249 blocker.Unblock(kNumWorkerThreads); |
191 tracker()->WaitUntilTasksComplete(kNumWorkerThreads); | 250 tracker()->WaitUntilTasksComplete(kNumWorkerThreads); |
192 | 251 |
193 // Clean up the task IDs we added. | 252 // Clean up the task IDs we added. |
194 tracker()->ClearCompleteSequence(); | 253 tracker()->ClearCompleteSequence(); |
195 } | 254 } |
196 | 255 |
197 protected: | |
198 // This closure will be executed right before the pool blocks on shutdown. | |
199 base::Closure before_wait_for_shutdown_; | |
200 | |
201 private: | 256 private: |
202 // SequencedWorkerPool::TestingObserver implementation. | 257 MessageLoop message_loop_; |
203 virtual void WillWaitForShutdown() { | 258 SequencedWorkerPoolOwner pool_owner_; |
204 if (!before_wait_for_shutdown_.is_null()) | |
205 before_wait_for_shutdown_.Run(); | |
206 } | |
207 | |
208 const scoped_refptr<SequencedWorkerPool> pool_; | |
209 const scoped_refptr<TestTracker> tracker_; | 259 const scoped_refptr<TestTracker> tracker_; |
210 }; | 260 }; |
211 | 261 |
212 // Checks that the given number of entries are in the tasks to complete of | 262 // Checks that the given number of entries are in the tasks to complete of |
213 // the given tracker, and then signals the given event the given number of | 263 // the given tracker, and then signals the given event the given number of |
214 // times. This is used to wakt up blocked background threads before blocking | 264 // times. This is used to wakt up blocked background threads before blocking |
215 // on shutdown. | 265 // on shutdown. |
216 void EnsureTasksToCompleteCountAndUnblock(scoped_refptr<TestTracker> tracker, | 266 void EnsureTasksToCompleteCountAndUnblock(scoped_refptr<TestTracker> tracker, |
217 size_t expected_tasks_to_complete, | 267 size_t expected_tasks_to_complete, |
218 ThreadBlocker* blocker, | 268 ThreadBlocker* blocker, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 | 315 |
266 std::vector<int> result = tracker()->WaitUntilTasksComplete(kNumTasks); | 316 std::vector<int> result = tracker()->WaitUntilTasksComplete(kNumTasks); |
267 EXPECT_EQ(kNumTasks, result.size()); | 317 EXPECT_EQ(kNumTasks, result.size()); |
268 } | 318 } |
269 | 319 |
270 // Tests that posting a bunch of tasks (many more than the number of | 320 // Tests that posting a bunch of tasks (many more than the number of |
271 // worker threads) to two pools simultaneously runs them all twice. | 321 // worker threads) to two pools simultaneously runs them all twice. |
272 // This test is meant to shake out any concurrency issues between | 322 // This test is meant to shake out any concurrency issues between |
273 // pools (like histograms). | 323 // pools (like histograms). |
274 TEST_F(SequencedWorkerPoolTest, LotsOfTasksTwoPools) { | 324 TEST_F(SequencedWorkerPoolTest, LotsOfTasksTwoPools) { |
275 scoped_refptr<SequencedWorkerPool> pool1( | 325 SequencedWorkerPoolOwner pool1(kNumWorkerThreads, "test1"); |
276 new SequencedWorkerPool(kNumWorkerThreads, "test1")); | 326 SequencedWorkerPoolOwner pool2(kNumWorkerThreads, "test2"); |
277 scoped_refptr<SequencedWorkerPool> pool2( | |
278 new SequencedWorkerPool(kNumWorkerThreads, "test2")); | |
279 | 327 |
280 base::Closure slow_task = base::Bind(&TestTracker::SlowTask, tracker(), 0); | 328 base::Closure slow_task = base::Bind(&TestTracker::SlowTask, tracker(), 0); |
281 pool1->PostWorkerTask(FROM_HERE, slow_task); | 329 pool1.pool()->PostWorkerTask(FROM_HERE, slow_task); |
282 pool2->PostWorkerTask(FROM_HERE, slow_task); | 330 pool2.pool()->PostWorkerTask(FROM_HERE, slow_task); |
283 | 331 |
284 const size_t kNumTasks = 20; | 332 const size_t kNumTasks = 20; |
285 for (size_t i = 1; i < kNumTasks; i++) { | 333 for (size_t i = 1; i < kNumTasks; i++) { |
286 base::Closure fast_task = | 334 base::Closure fast_task = |
287 base::Bind(&TestTracker::FastTask, tracker(), i); | 335 base::Bind(&TestTracker::FastTask, tracker(), i); |
288 pool1->PostWorkerTask(FROM_HERE, fast_task); | 336 pool1.pool()->PostWorkerTask(FROM_HERE, fast_task); |
289 pool2->PostWorkerTask(FROM_HERE, fast_task); | 337 pool2.pool()->PostWorkerTask(FROM_HERE, fast_task); |
290 } | 338 } |
291 | 339 |
292 std::vector<int> result = | 340 std::vector<int> result = |
293 tracker()->WaitUntilTasksComplete(2*kNumTasks); | 341 tracker()->WaitUntilTasksComplete(2*kNumTasks); |
294 EXPECT_EQ(2*kNumTasks, result.size()); | 342 EXPECT_EQ(2*kNumTasks, result.size()); |
| 343 |
| 344 pool2.pool()->Shutdown(); |
| 345 pool1.pool()->Shutdown(); |
295 } | 346 } |
296 | 347 |
297 // Test that tasks with the same sequence token are executed in order but don't | 348 // Test that tasks with the same sequence token are executed in order but don't |
298 // affect other tasks. | 349 // affect other tasks. |
299 TEST_F(SequencedWorkerPoolTest, Sequence) { | 350 TEST_F(SequencedWorkerPoolTest, Sequence) { |
300 // Fill all the worker threads except one. | 351 // Fill all the worker threads except one. |
301 const size_t kNumBackgroundTasks = kNumWorkerThreads - 1; | 352 const size_t kNumBackgroundTasks = kNumWorkerThreads - 1; |
302 ThreadBlocker background_blocker; | 353 ThreadBlocker background_blocker; |
303 for (size_t i = 0; i < kNumBackgroundTasks; i++) { | 354 for (size_t i = 0; i < kNumBackgroundTasks; i++) { |
304 pool()->PostWorkerTask(FROM_HERE, | 355 pool()->PostWorkerTask(FROM_HERE, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 pool()->PostWorkerTaskWithShutdownBehavior( | 427 pool()->PostWorkerTaskWithShutdownBehavior( |
377 FROM_HERE, | 428 FROM_HERE, |
378 base::Bind(&TestTracker::FastTask, tracker(), 101), | 429 base::Bind(&TestTracker::FastTask, tracker(), 101), |
379 SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 430 SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
380 pool()->PostWorkerTaskWithShutdownBehavior( | 431 pool()->PostWorkerTaskWithShutdownBehavior( |
381 FROM_HERE, | 432 FROM_HERE, |
382 base::Bind(&TestTracker::FastTask, tracker(), 102), | 433 base::Bind(&TestTracker::FastTask, tracker(), 102), |
383 SequencedWorkerPool::BLOCK_SHUTDOWN); | 434 SequencedWorkerPool::BLOCK_SHUTDOWN); |
384 | 435 |
385 // Shutdown the worker pool. This should discard all non-blocking tasks. | 436 // Shutdown the worker pool. This should discard all non-blocking tasks. |
386 before_wait_for_shutdown_ = | 437 SetWillWaitForShutdownCallback( |
387 base::Bind(&EnsureTasksToCompleteCountAndUnblock, | 438 base::Bind(&EnsureTasksToCompleteCountAndUnblock, |
388 scoped_refptr<TestTracker>(tracker()), 0, | 439 scoped_refptr<TestTracker>(tracker()), 0, |
389 &blocker, kNumWorkerThreads); | 440 &blocker, kNumWorkerThreads)); |
390 pool()->Shutdown(); | 441 pool()->Shutdown(); |
391 | 442 |
392 std::vector<int> result = tracker()->WaitUntilTasksComplete(4); | 443 std::vector<int> result = tracker()->WaitUntilTasksComplete(4); |
393 | 444 |
394 // The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN | 445 // The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN |
395 // one, in no particular order. | 446 // one, in no particular order. |
396 ASSERT_EQ(4u, result.size()); | 447 ASSERT_EQ(4u, result.size()); |
397 for (size_t i = 0; i < kNumWorkerThreads; i++) { | 448 for (size_t i = 0; i < kNumWorkerThreads; i++) { |
398 EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) != | 449 EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) != |
399 result.end()); | 450 result.end()); |
(...skipping 29 matching lines...) Expand all Loading... |
429 EXPECT_EQ(1u, result.size()); | 480 EXPECT_EQ(1u, result.size()); |
430 } | 481 } |
431 | 482 |
432 class SequencedWorkerPoolTaskRunnerTestDelegate { | 483 class SequencedWorkerPoolTaskRunnerTestDelegate { |
433 public: | 484 public: |
434 SequencedWorkerPoolTaskRunnerTestDelegate() {} | 485 SequencedWorkerPoolTaskRunnerTestDelegate() {} |
435 | 486 |
436 ~SequencedWorkerPoolTaskRunnerTestDelegate() {} | 487 ~SequencedWorkerPoolTaskRunnerTestDelegate() {} |
437 | 488 |
438 void StartTaskRunner() { | 489 void StartTaskRunner() { |
439 worker_pool_ = | 490 pool_owner_.reset( |
440 new SequencedWorkerPool(10, "SequencedWorkerPoolTaskRunnerTest"); | 491 new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest")); |
441 } | 492 } |
442 | 493 |
443 scoped_refptr<SequencedWorkerPool> GetTaskRunner() { | 494 scoped_refptr<SequencedWorkerPool> GetTaskRunner() { |
444 return worker_pool_; | 495 return pool_owner_->pool(); |
445 } | 496 } |
446 | 497 |
447 void StopTaskRunner() { | 498 void StopTaskRunner() { |
448 worker_pool_->Shutdown(); | 499 pool_owner_->pool()->Shutdown(); |
449 worker_pool_ = NULL; | 500 // Don't reset |pool_owner_| here, as the test may still hold a |
| 501 // reference to the pool. |
450 } | 502 } |
451 | 503 |
452 bool TaskRunnerHandlesNonZeroDelays() const { | 504 bool TaskRunnerHandlesNonZeroDelays() const { |
453 // TODO(akalin): Set this to true once SequencedWorkerPool handles | 505 // TODO(akalin): Set this to true once SequencedWorkerPool handles |
454 // non-zero delays. | 506 // non-zero delays. |
455 return false; | 507 return false; |
456 } | 508 } |
457 | 509 |
458 private: | 510 private: |
459 scoped_refptr<SequencedWorkerPool> worker_pool_; | 511 MessageLoop message_loop_; |
| 512 scoped_ptr<SequencedWorkerPoolOwner> pool_owner_; |
460 }; | 513 }; |
461 | 514 |
462 INSTANTIATE_TYPED_TEST_CASE_P( | 515 INSTANTIATE_TYPED_TEST_CASE_P( |
463 SequencedWorkerPool, TaskRunnerTest, | 516 SequencedWorkerPool, TaskRunnerTest, |
464 SequencedWorkerPoolTaskRunnerTestDelegate); | 517 SequencedWorkerPoolTaskRunnerTestDelegate); |
465 | 518 |
466 } // namespace | 519 } // namespace |
467 | 520 |
468 } // namespace base | 521 } // namespace base |
OLD | NEW |