Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(705)

Side by Side Diff: base/threading/sequenced_worker_pool_unittest.cc

Issue 9558007: Ensure that SequencedWorkerPools in tests don't outlive their tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix test failures Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « base/threading/sequenced_worker_pool.cc ('k') | chrome/browser/autocomplete/autocomplete_edit_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698