summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-07 01:35:37 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-07 01:35:37 +0000
commit13ecb5e99e5fad75162cad08f1082eff259ff0d9 (patch)
tree988e3a5dc1b8fc33e4e28dd2826e8c0176350cd4 /base
parent8c2acc21b17cdcc88edc0bea2623a637c97fdeab (diff)
downloadchromium_src-13ecb5e99e5fad75162cad08f1082eff259ff0d9.zip
chromium_src-13ecb5e99e5fad75162cad08f1082eff259ff0d9.tar.gz
chromium_src-13ecb5e99e5fad75162cad08f1082eff259ff0d9.tar.bz2
Flush SequenceWorkerPool tasks after each test. Applies to unit_test, interactive_ui test, browser_tests... pretty much all gtest based content library test harnesses are affected.
The CL changes semantics and implementation of the existing FlushForTesting method (which wasn't suitable for this usage). * The old method would wait for delayed tasks prior to continuing, the new method will not run them but will delete them prior to continuing. * The old method would deadlock if called after Shutdown had been called, the new method returns immediately in that case. A few SWP unittests relied on the waiting for delayed task completion behavior. Those have been modified to explicitly wait thru other means. BUG=168415,166470 Review URL: https://codereview.chromium.org/11649032 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@186578 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/test/sequenced_task_runner_test_template.cc13
-rw-r--r--base/test/sequenced_task_runner_test_template.h17
-rw-r--r--base/test/task_runner_test_template.cc14
-rw-r--r--base/test/task_runner_test_template.h14
-rw-r--r--base/threading/sequenced_worker_pool.cc114
-rw-r--r--base/threading/sequenced_worker_pool.h1
-rw-r--r--base/threading/sequenced_worker_pool_unittest.cc81
7 files changed, 211 insertions, 43 deletions
diff --git a/base/test/sequenced_task_runner_test_template.cc b/base/test/sequenced_task_runner_test_template.cc
index 50487d2..010f439 100644
--- a/base/test/sequenced_task_runner_test_template.cc
+++ b/base/test/sequenced_task_runner_test_template.cc
@@ -16,7 +16,10 @@ TaskEvent::TaskEvent(int i, Type type)
: i(i), type(type) {
}
-SequencedTaskTracker::SequencedTaskTracker() : next_post_i_(0) {
+SequencedTaskTracker::SequencedTaskTracker()
+ : next_post_i_(0),
+ task_end_count_(0),
+ task_end_cv_(&lock_) {
}
void SequencedTaskTracker::PostWrappedNonNestableTask(
@@ -81,6 +84,8 @@ void SequencedTaskTracker::TaskStarted(int i) {
void SequencedTaskTracker::TaskEnded(int i) {
AutoLock lock(lock_);
events_.push_back(TaskEvent(i, TaskEvent::END));
+ ++task_end_count_;
+ task_end_cv_.Signal();
}
const std::vector<TaskEvent>&
@@ -88,6 +93,12 @@ SequencedTaskTracker::GetTaskEvents() const {
return events_;
}
+void SequencedTaskTracker::WaitForCompletedTasks(int count) {
+ AutoLock lock(lock_);
+ while (task_end_count_ < count)
+ task_end_cv_.Wait();
+}
+
SequencedTaskTracker::~SequencedTaskTracker() {
}
diff --git a/base/test/sequenced_task_runner_test_template.h b/base/test/sequenced_task_runner_test_template.h
index 0c8d135..761eefd 100644
--- a/base/test/sequenced_task_runner_test_template.h
+++ b/base/test/sequenced_task_runner_test_template.h
@@ -18,6 +18,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
+#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -61,6 +62,9 @@ class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
const std::vector<TaskEvent>& GetTaskEvents() const;
+ // Returns after the tracker observes a total of |count| task completions.
+ void WaitForCompletedTasks(int count);
+
private:
friend class RefCountedThreadSafe<SequencedTaskTracker>;
@@ -79,7 +83,7 @@ class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
// Records a end event for task |i|.
void TaskEnded(int i);
- // Protects events_ and next_post_i_.
+ // Protects events_, next_post_i_, task_end_count_ and task_end_cv_.
Lock lock_;
// The events as they occurred for each task (protected by lock_).
@@ -89,6 +93,10 @@ class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
// lock_).
int next_post_i_;
+ // The number of task end events we've received.
+ int task_end_count_;
+ ConditionVariable task_end_cv_;
+
DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
};
@@ -112,7 +120,7 @@ template <typename TaskRunnerTestDelegate>
class SequencedTaskRunnerTest : public testing::Test {
protected:
SequencedTaskRunnerTest()
- : task_tracker_(new internal::SequencedTaskTracker()) {}
+ : task_tracker_(new internal::SequencedTaskTracker()) {}
const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
TaskRunnerTestDelegate delegate_;
@@ -191,6 +199,7 @@ TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
TimeDelta::FromMilliseconds(kDelayIncrementMs * i));
}
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
@@ -244,6 +253,7 @@ TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskBasic) {
Time time_before_run = Time::Now();
this->task_tracker_->PostWrappedDelayedNonNestableTask(
task_runner, Closure(), kDelay);
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
this->delegate_.StopTaskRunner();
Time time_after_run = Time::Now();
@@ -278,6 +288,7 @@ TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTasksSameDelay) {
task_runner, Closure(), kDelay);
this->task_tracker_->PostWrappedDelayedNonNestableTask(
task_runner, Closure(), kDelay);
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
@@ -306,6 +317,7 @@ TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterLongTask) {
TimeDelta::FromMilliseconds(50)));
this->task_tracker_->PostWrappedDelayedNonNestableTask(
task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
@@ -335,6 +347,7 @@ TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterManyLongTasks) {
}
this->task_tracker_->PostWrappedDelayedNonNestableTask(
task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+ this->task_tracker_->WaitForCompletedTasks(kTaskCount);
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
diff --git a/base/test/task_runner_test_template.cc b/base/test/task_runner_test_template.cc
index 239a99f..b756203 100644
--- a/base/test/task_runner_test_template.cc
+++ b/base/test/task_runner_test_template.cc
@@ -8,7 +8,7 @@ namespace base {
namespace internal {
-TaskTracker::TaskTracker() {}
+TaskTracker::TaskTracker() : task_runs_(0), task_runs_cv_(&lock_) {}
TaskTracker::~TaskTracker() {}
@@ -17,18 +17,26 @@ Closure TaskTracker::WrapTask(const Closure& task, int i) {
}
void TaskTracker::RunTask(const Closure& task, int i) {
- AutoLock lock(task_run_counts_lock_);
+ AutoLock lock(lock_);
if (!task.is_null()) {
task.Run();
}
++task_run_counts_[i];
+ ++task_runs_;
+ task_runs_cv_.Signal();
}
std::map<int, int> TaskTracker::GetTaskRunCounts() const {
- AutoLock lock(task_run_counts_lock_);
+ AutoLock lock(lock_);
return task_run_counts_;
}
+void TaskTracker::WaitForCompletedTasks(int count) {
+ AutoLock lock(lock_);
+ while (task_runs_ < count)
+ task_runs_cv_.Wait();
+}
+
void ExpectRunsTasksOnCurrentThread(
bool expected_value,
const scoped_refptr<TaskRunner>& task_runner) {
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
index 437a7d9..2dd8814 100644
--- a/base/test/task_runner_test_template.h
+++ b/base/test/task_runner_test_template.h
@@ -25,7 +25,8 @@
// }
//
// // Stop the task runner and make sure all tasks posted before
-// // this is called are run.
+// // this is called are run. Caveat: delayed tasks are not run,
+ // they're simply deleted.
// void StopTaskRunner() {
// ...
// }
@@ -58,6 +59,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
#include "base/threading/thread.h"
@@ -81,6 +83,9 @@ class TaskTracker : public RefCountedThreadSafe<TaskTracker> {
std::map<int, int> GetTaskRunCounts() const;
+ // Returns after the tracker observes a total of |count| task completions.
+ void WaitForCompletedTasks(int count);
+
private:
friend class RefCountedThreadSafe<TaskTracker>;
@@ -88,8 +93,10 @@ class TaskTracker : public RefCountedThreadSafe<TaskTracker> {
void RunTask(const Closure& task, int i);
- mutable Lock task_run_counts_lock_;
+ mutable Lock lock_;
std::map<int, int> task_run_counts_;
+ int task_runs_;
+ ConditionVariable task_runs_cv_;
DISALLOW_COPY_AND_ASSIGN(TaskTracker);
};
@@ -140,6 +147,7 @@ TYPED_TEST_P(TaskRunnerTest, Delayed) {
}
std::map<int, int> expected_task_run_counts;
+ int expected_total_tasks = 0;
this->delegate_.StartTaskRunner();
scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
@@ -150,8 +158,10 @@ TYPED_TEST_P(TaskRunnerTest, Delayed) {
task_runner->PostDelayedTask(
FROM_HERE, ith_task, base::TimeDelta::FromMilliseconds(j));
++expected_task_run_counts[i];
+ ++expected_total_tasks;
}
}
+ this->task_tracker_->WaitForCompletedTasks(expected_total_tasks);
this->delegate_.StopTaskRunner();
EXPECT_EQ(expected_task_run_counts,
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
index 12b7564..f89a582 100644
--- a/base/threading/sequenced_worker_pool.cc
+++ b/base/threading/sequenced_worker_pool.cc
@@ -281,7 +281,7 @@ class SequencedWorkerPool::Inner {
bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
- void FlushForTesting();
+ void CleanupForTesting();
void SignalHasWorkForTesting();
@@ -299,9 +299,13 @@ class SequencedWorkerPool::Inner {
GET_WORK_WAIT,
};
- // Returns whether there are no more pending tasks and all threads
- // are idle. Must be called under lock.
- bool IsIdle() const;
+ enum CleanupState {
+ CLEANUP_REQUESTED,
+ CLEANUP_STARTING,
+ CLEANUP_RUNNING,
+ CLEANUP_FINISHING,
+ CLEANUP_DONE,
+ };
// Called from within the lock, this converts the given token name into a
// token ID, creating a new one if necessary.
@@ -334,6 +338,8 @@ class SequencedWorkerPool::Inner {
TimeDelta* wait_time,
std::vector<Closure>* delete_these_outside_lock);
+ void HandleCleanup();
+
// Peforms init and cleanup around running the given task. WillRun...
// returns the value from PrepareToStartAdditionalThreadIfNecessary.
// The calling code should call FinishStartingAdditionalThread once the
@@ -389,10 +395,6 @@ class SequencedWorkerPool::Inner {
ConditionVariable has_work_cv_;
// Condition variable that is waited on by non-worker threads (in
- // FlushForTesting()) until IsIdle() goes to true.
- ConditionVariable is_idle_cv_;
-
- // Condition variable that is waited on by non-worker threads (in
// Shutdown()) until CanShutdown() goes to true.
ConditionVariable can_shutdown_cv_;
@@ -450,6 +452,11 @@ class SequencedWorkerPool::Inner {
// has been called.
int max_blocking_tasks_after_shutdown_;
+ // State used to cleanup for testing, all guarded by lock_.
+ CleanupState cleanup_state_;
+ size_t cleanup_idlers_;
+ ConditionVariable cleanup_cv_;
+
TestingObserver* const testing_observer_;
DISALLOW_COPY_AND_ASSIGN(Inner);
@@ -493,7 +500,6 @@ SequencedWorkerPool::Inner::Inner(
last_sequence_number_(0),
lock_(),
has_work_cv_(&lock_),
- is_idle_cv_(&lock_),
can_shutdown_cv_(&lock_),
max_threads_(max_threads),
thread_name_prefix_(thread_name_prefix),
@@ -505,6 +511,9 @@ SequencedWorkerPool::Inner::Inner(
trace_id_(0),
shutdown_called_(false),
max_blocking_tasks_after_shutdown_(0),
+ cleanup_state_(CLEANUP_DONE),
+ cleanup_idlers_(0),
+ cleanup_cv_(&lock_),
testing_observer_(observer) {}
SequencedWorkerPool::Inner::~Inner() {
@@ -609,10 +618,21 @@ bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread(
return found->second->running_sequence().Equals(sequence_token);
}
-void SequencedWorkerPool::Inner::FlushForTesting() {
+// See https://code.google.com/p/chromium/issues/detail?id=168415
+void SequencedWorkerPool::Inner::CleanupForTesting() {
+ DCHECK(!RunsTasksOnCurrentThread());
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
AutoLock lock(lock_);
- while (!IsIdle())
- is_idle_cv_.Wait();
+ CHECK_EQ(CLEANUP_DONE, cleanup_state_);
+ if (shutdown_called_)
+ return;
+ if (pending_tasks_.empty() && waiting_thread_count_ == threads_.size())
+ return;
+ cleanup_state_ = CLEANUP_REQUESTED;
+ cleanup_idlers_ = 0;
+ has_work_cv_.Signal();
+ while (cleanup_state_ != CLEANUP_DONE)
+ cleanup_cv_.Wait();
}
void SequencedWorkerPool::Inner::SignalHasWorkForTesting() {
@@ -624,7 +644,8 @@ void SequencedWorkerPool::Inner::Shutdown(
DCHECK_GE(max_new_blocking_tasks_after_shutdown, 0);
{
AutoLock lock(lock_);
-
+ // Cleanup and Shutdown should not be called concurrently.
+ CHECK_EQ(CLEANUP_DONE, cleanup_state_);
if (shutdown_called_)
return;
shutdown_called_ = true;
@@ -672,6 +693,8 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
base::mac::ScopedNSAutoreleasePool autorelease_pool;
#endif
+ HandleCleanup();
+
// See GetWork for what delete_these_outside_lock is doing.
SequencedTask task;
TimeDelta wait_time;
@@ -720,6 +743,21 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
SequenceToken(), CONTINUE_ON_SHUTDOWN);
}
DidRunWorkerTask(task); // Must be done inside the lock.
+ } else if (cleanup_state_ == CLEANUP_RUNNING) {
+ switch (status) {
+ case GET_WORK_WAIT: {
+ AutoUnlock unlock(lock_);
+ delete_these_outside_lock.clear();
+ }
+ break;
+ case GET_WORK_NOT_FOUND:
+ CHECK(delete_these_outside_lock.empty());
+ cleanup_state_ = CLEANUP_FINISHING;
+ cleanup_cv_.Broadcast();
+ break;
+ default:
+ NOTREACHED();
+ }
} else {
// When we're terminating and there's no more work, we can
// shut down, other workers can complete any pending or new tasks.
@@ -733,9 +771,6 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
blocking_shutdown_pending_task_count_ == 0)
break;
waiting_thread_count_++;
- // This is the only time that IsIdle() can go to true.
- if (IsIdle())
- is_idle_cv_.Signal();
switch (status) {
case GET_WORK_NOT_FOUND:
@@ -760,9 +795,44 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
can_shutdown_cv_.Signal();
}
-bool SequencedWorkerPool::Inner::IsIdle() const {
+void SequencedWorkerPool::Inner::HandleCleanup() {
lock_.AssertAcquired();
- return pending_tasks_.empty() && waiting_thread_count_ == threads_.size();
+ if (cleanup_state_ == CLEANUP_DONE)
+ return;
+ if (cleanup_state_ == CLEANUP_REQUESTED) {
+ // We win, we get to do the cleanup as soon as the others wise up and idle.
+ cleanup_state_ = CLEANUP_STARTING;
+ while (thread_being_created_ ||
+ cleanup_idlers_ != threads_.size() - 1) {
+ has_work_cv_.Signal();
+ cleanup_cv_.Wait();
+ }
+ cleanup_state_ = CLEANUP_RUNNING;
+ return;
+ }
+ if (cleanup_state_ == CLEANUP_STARTING) {
+ // Another worker thread is cleaning up, we idle here until thats done.
+ ++cleanup_idlers_;
+ cleanup_cv_.Broadcast();
+ while (cleanup_state_ != CLEANUP_FINISHING) {
+ cleanup_cv_.Wait();
+ }
+ --cleanup_idlers_;
+ cleanup_cv_.Broadcast();
+ return;
+ }
+ if (cleanup_state_ == CLEANUP_FINISHING) {
+ // We wait for all idlers to wake up prior to being DONE.
+ while (cleanup_idlers_ != 0) {
+ cleanup_cv_.Broadcast();
+ cleanup_cv_.Wait();
+ }
+ if (cleanup_state_ == CLEANUP_FINISHING) {
+ cleanup_state_ = CLEANUP_DONE;
+ cleanup_cv_.Signal();
+ }
+ return;
+ }
}
int SequencedWorkerPool::Inner::LockedGetNamedTokenID(
@@ -866,6 +936,11 @@ SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork(
// The time to run has not come yet.
*wait_time = i->time_to_run - current_time;
status = GET_WORK_WAIT;
+ if (cleanup_state_ == CLEANUP_RUNNING) {
+ // Deferred tasks are deleted when cleaning up, see Inner::ThreadLoop.
+ delete_these_outside_lock->push_back(i->task);
+ pending_tasks_.erase(i);
+ }
break;
}
@@ -972,6 +1047,7 @@ int SequencedWorkerPool::Inner::PrepareToStartAdditionalThreadIfHelpful() {
// shutdown call.
if (!shutdown_called_ &&
!thread_being_created_ &&
+ cleanup_state_ == CLEANUP_DONE &&
threads_.size() < max_threads_ &&
waiting_thread_count_ == 0) {
// We could use an additional thread if there's work to be done.
@@ -1150,7 +1226,7 @@ bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread(
}
void SequencedWorkerPool::FlushForTesting() {
- inner_->FlushForTesting();
+ inner_->CleanupForTesting();
}
void SequencedWorkerPool::SignalHasWorkForTesting() {
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
index 9c7108e..a96cd76 100644
--- a/base/threading/sequenced_worker_pool.h
+++ b/base/threading/sequenced_worker_pool.h
@@ -288,6 +288,7 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// Blocks until all pending tasks are complete. This should only be called in
// unit tests when you want to validate something that should have happened.
+ // This will not flush delayed tasks; delayed tasks get deleted.
//
// Note that calling this will not prevent other threads from posting work to
// the queue while the calling thread is waiting on Flush(). In this case,
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
index 74d23fc..f0caf1a 100644
--- a/base/threading/sequenced_worker_pool_unittest.cc
+++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -99,16 +99,18 @@ class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
SignalWorkerDone(id);
}
- void PostAdditionalTasks(int id, SequencedWorkerPool* pool) {
+ void PostAdditionalTasks(
+ int id, SequencedWorkerPool* pool,
+ bool expected_return_value) {
Closure fast_task = base::Bind(&TestTracker::FastTask, this, 100);
- EXPECT_FALSE(
- pool->PostWorkerTaskWithShutdownBehavior(
- FROM_HERE, fast_task,
- SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
- EXPECT_FALSE(
- pool->PostWorkerTaskWithShutdownBehavior(
- FROM_HERE, fast_task,
- SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+ EXPECT_EQ(expected_return_value,
+ pool->PostWorkerTaskWithShutdownBehavior(
+ FROM_HERE, fast_task,
+ SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+ EXPECT_EQ(expected_return_value,
+ pool->PostWorkerTaskWithShutdownBehavior(
+ FROM_HERE, fast_task,
+ SequencedWorkerPool::SKIP_ON_SHUTDOWN));
pool->PostWorkerTaskWithShutdownBehavior(
FROM_HERE, fast_task,
SequencedWorkerPool::BLOCK_SHUTDOWN);
@@ -139,6 +141,11 @@ class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
return ret;
}
+ size_t GetTasksCompletedCount() {
+ base::AutoLock lock(lock_);
+ return complete_sequence_.size();
+ }
+
void ClearCompleteSequence() {
base::AutoLock lock(lock_);
complete_sequence_.clear();
@@ -517,7 +524,8 @@ TEST_F(SequencedWorkerPoolTest, AllowsAfterShutdown) {
for (int i = 0; i < kNumQueuedTasks; ++i) {
EXPECT_TRUE(pool()->PostWorkerTaskWithShutdownBehavior(
FROM_HERE,
- base::Bind(&TestTracker::PostAdditionalTasks, tracker(), i, pool()),
+ base::Bind(&TestTracker::PostAdditionalTasks, tracker(), i, pool(),
+ false),
SequencedWorkerPool::BLOCK_SHUTDOWN));
}
@@ -749,6 +757,47 @@ TEST_F(SequencedWorkerPoolTest, IsRunningOnCurrentThread) {
unused_pool->Shutdown();
}
+// Verify that FlushForTesting works as intended.
+TEST_F(SequencedWorkerPoolTest, FlushForTesting) {
+ // Should be fine to call on a new instance.
+ pool()->FlushForTesting();
+
+ // Queue up a bunch of work, including a long delayed task and
+ // a task that produces additional tasks as an artifact.
+ pool()->PostDelayedWorkerTask(
+ FROM_HERE,
+ base::Bind(&TestTracker::FastTask, tracker(), 0),
+ TimeDelta::FromMinutes(5));
+ pool()->PostWorkerTask(FROM_HERE,
+ base::Bind(&TestTracker::SlowTask, tracker(), 0));
+ const size_t kNumFastTasks = 20;
+ for (size_t i = 0; i < kNumFastTasks; i++) {
+ pool()->PostWorkerTask(FROM_HERE,
+ base::Bind(&TestTracker::FastTask, tracker(), 0));
+ }
+ pool()->PostWorkerTask(
+ FROM_HERE,
+ base::Bind(&TestTracker::PostAdditionalTasks, tracker(), 0, pool(),
+ true));
+
+ // We expect all except the delayed task to have been run. We verify all
+ // closures have been deleted deleted by looking at the refcount of the
+ // tracker.
+ EXPECT_FALSE(tracker()->HasOneRef());
+ pool()->FlushForTesting();
+ EXPECT_TRUE(tracker()->HasOneRef());
+ EXPECT_EQ(1 + kNumFastTasks + 1 + 3, tracker()->GetTasksCompletedCount());
+
+ // Should be fine to call on an idle instance with all threads created, and
+ // spamming the method shouldn't deadlock or confuse the class.
+ pool()->FlushForTesting();
+ pool()->FlushForTesting();
+
+ // Should be fine to call after shutdown too.
+ pool()->Shutdown();
+ pool()->FlushForTesting();
+}
+
class SequencedWorkerPoolTaskRunnerTestDelegate {
public:
SequencedWorkerPoolTaskRunnerTestDelegate() {}
@@ -765,8 +814,8 @@ class SequencedWorkerPoolTaskRunnerTestDelegate {
}
void StopTaskRunner() {
- // Make sure all tasks (including delayed ones) are run before shutting
- // down.
+ // Make sure all tasks are run before shutting down. Delayed tasks are
+ // not run, they're simply deleted.
pool_owner_->pool()->FlushForTesting();
pool_owner_->pool()->Shutdown();
// Don't reset |pool_owner_| here, as the test may still hold a
@@ -805,8 +854,8 @@ class SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate {
}
void StopTaskRunner() {
- // Make sure all tasks (including delayed ones) are run before shutting
- // down.
+ // Make sure all tasks are run before shutting down. Delayed tasks are
+ // not run, they're simply deleted.
pool_owner_->pool()->FlushForTesting();
pool_owner_->pool()->Shutdown();
// Don't reset |pool_owner_| here, as the test may still hold a
@@ -846,8 +895,8 @@ class SequencedWorkerPoolSequencedTaskRunnerTestDelegate {
}
void StopTaskRunner() {
- // Make sure all tasks (including delayed ones) are run before shutting
- // down.
+ // Make sure all tasks are run before shutting down. Delayed tasks are
+ // not run, they're simply deleted.
pool_owner_->pool()->FlushForTesting();
pool_owner_->pool()->Shutdown();
// Don't reset |pool_owner_| here, as the test may still hold a