185 lines
5.5 KiB
C++
185 lines
5.5 KiB
C++
|
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "base/deferred_sequenced_task_runner.h"
|
||
|
|
||
|
#include "base/basictypes.h"
|
||
|
#include "base/bind.h"
|
||
|
#include "base/bind_helpers.h"
|
||
|
#include "base/memory/ref_counted.h"
|
||
|
#include "base/message_loop/message_loop.h"
|
||
|
#include "base/message_loop/message_loop_proxy.h"
|
||
|
#include "base/threading/non_thread_safe.h"
|
||
|
#include "base/threading/thread.h"
|
||
|
#include "testing/gmock/include/gmock/gmock.h"
|
||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
class DeferredSequencedTaskRunnerTest : public testing::Test,
|
||
|
public base::NonThreadSafe {
|
||
|
public:
|
||
|
class ExecuteTaskOnDestructor :
|
||
|
public base::RefCounted<ExecuteTaskOnDestructor> {
|
||
|
public:
|
||
|
ExecuteTaskOnDestructor(
|
||
|
DeferredSequencedTaskRunnerTest* executor,
|
||
|
int task_id)
|
||
|
: executor_(executor),
|
||
|
task_id_(task_id) {
|
||
|
}
|
||
|
private:
|
||
|
friend class base::RefCounted<ExecuteTaskOnDestructor>;
|
||
|
virtual ~ExecuteTaskOnDestructor() {
|
||
|
executor_->ExecuteTask(task_id_);
|
||
|
}
|
||
|
DeferredSequencedTaskRunnerTest* executor_;
|
||
|
int task_id_;
|
||
|
};
|
||
|
|
||
|
void ExecuteTask(int task_id) {
|
||
|
base::AutoLock lock(lock_);
|
||
|
executed_task_ids_.push_back(task_id);
|
||
|
}
|
||
|
|
||
|
void PostExecuteTask(int task_id) {
|
||
|
runner_->PostTask(FROM_HERE,
|
||
|
base::Bind(&DeferredSequencedTaskRunnerTest::ExecuteTask,
|
||
|
base::Unretained(this),
|
||
|
task_id));
|
||
|
}
|
||
|
|
||
|
void StartRunner() {
|
||
|
runner_->Start();
|
||
|
}
|
||
|
|
||
|
void DoNothing(ExecuteTaskOnDestructor* object) {
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
DeferredSequencedTaskRunnerTest() :
|
||
|
loop_(),
|
||
|
runner_(
|
||
|
new base::DeferredSequencedTaskRunner(loop_.message_loop_proxy())) {
|
||
|
}
|
||
|
|
||
|
base::MessageLoop loop_;
|
||
|
scoped_refptr<base::DeferredSequencedTaskRunner> runner_;
|
||
|
mutable base::Lock lock_;
|
||
|
std::vector<int> executed_task_ids_;
|
||
|
};
|
||
|
|
||
|
TEST_F(DeferredSequencedTaskRunnerTest, Stopped) {
|
||
|
PostExecuteTask(1);
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
|
||
|
}
|
||
|
|
||
|
TEST_F(DeferredSequencedTaskRunnerTest, Start) {
|
||
|
StartRunner();
|
||
|
PostExecuteTask(1);
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
|
||
|
}
|
||
|
|
||
|
TEST_F(DeferredSequencedTaskRunnerTest, StartWithMultipleElements) {
|
||
|
StartRunner();
|
||
|
for (int i = 1; i < 5; ++i)
|
||
|
PostExecuteTask(i);
|
||
|
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4));
|
||
|
}
|
||
|
|
||
|
TEST_F(DeferredSequencedTaskRunnerTest, DeferredStart) {
|
||
|
PostExecuteTask(1);
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
|
||
|
|
||
|
StartRunner();
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
|
||
|
|
||
|
PostExecuteTask(2);
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2));
|
||
|
}
|
||
|
|
||
|
TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleElements) {
|
||
|
for (int i = 1; i < 5; ++i)
|
||
|
PostExecuteTask(i);
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
|
||
|
|
||
|
StartRunner();
|
||
|
for (int i = 5; i < 9; ++i)
|
||
|
PostExecuteTask(i);
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4, 5, 6, 7, 8));
|
||
|
}
|
||
|
|
||
|
TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) {
|
||
|
{
|
||
|
base::Thread thread1("DeferredSequencedTaskRunnerTestThread1");
|
||
|
base::Thread thread2("DeferredSequencedTaskRunnerTestThread2");
|
||
|
thread1.Start();
|
||
|
thread2.Start();
|
||
|
for (int i = 0; i < 5; ++i) {
|
||
|
thread1.message_loop()->PostTask(
|
||
|
FROM_HERE,
|
||
|
base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
|
||
|
base::Unretained(this),
|
||
|
2 * i));
|
||
|
thread2.message_loop()->PostTask(
|
||
|
FROM_HERE,
|
||
|
base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
|
||
|
base::Unretained(this),
|
||
|
2 * i + 1));
|
||
|
if (i == 2) {
|
||
|
thread1.message_loop()->PostTask(
|
||
|
FROM_HERE,
|
||
|
base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
|
||
|
base::Unretained(this)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
loop_.RunUntilIdle();
|
||
|
EXPECT_THAT(executed_task_ids_,
|
||
|
testing::WhenSorted(testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)));
|
||
|
}
|
||
|
|
||
|
TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) {
|
||
|
{
|
||
|
base::Thread thread("DeferredSequencedTaskRunnerTestThread");
|
||
|
thread.Start();
|
||
|
runner_ =
|
||
|
new base::DeferredSequencedTaskRunner(thread.message_loop_proxy());
|
||
|
for (int i = 0; i < 5; ++i) {
|
||
|
{
|
||
|
// Use a block to ensure that no reference to |short_lived_object|
|
||
|
// is kept on the main thread after it is posted to |runner_|.
|
||
|
scoped_refptr<ExecuteTaskOnDestructor> short_lived_object =
|
||
|
new ExecuteTaskOnDestructor(this, 2 * i);
|
||
|
runner_->PostTask(
|
||
|
FROM_HERE,
|
||
|
base::Bind(&DeferredSequencedTaskRunnerTest::DoNothing,
|
||
|
base::Unretained(this),
|
||
|
short_lived_object));
|
||
|
}
|
||
|
// |short_lived_object| with id |2 * i| should be destroyed before the
|
||
|
// task |2 * i + 1| is executed.
|
||
|
PostExecuteTask(2 * i + 1);
|
||
|
}
|
||
|
StartRunner();
|
||
|
}
|
||
|
|
||
|
// All |short_lived_object| with id |2 * i| are destroyed before the task
|
||
|
// |2 * i + 1| is executed.
|
||
|
EXPECT_THAT(executed_task_ids_,
|
||
|
testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
|
||
|
}
|
||
|
|
||
|
} // namespace
|