1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/test/ordered_simple_task_runner.h"
13 #include "base/auto_reset.h"
14 #include "base/debug/trace_event.h"
15 #include "base/debug/trace_event_argument.h"
16 #include "base/strings/string_number_conversions.h"
18 #define TRACE_TASK(function, task) \
19 TRACE_EVENT_INSTANT1( \
20 "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue());
22 #define TRACE_TASK_RUN(function, tag, task)
26 // TestOrderablePendingTask implementation
27 TestOrderablePendingTask::TestOrderablePendingTask()
28 : base::TestPendingTask(),
29 task_id_(TestOrderablePendingTask::task_id_counter++) {
32 TestOrderablePendingTask::TestOrderablePendingTask(
33 const tracked_objects::Location& location,
34 const base::Closure& task,
35 base::TimeTicks post_time,
36 base::TimeDelta delay,
37 TestNestability nestability)
38 : base::TestPendingTask(location, task, post_time, delay, nestability),
39 task_id_(TestOrderablePendingTask::task_id_counter++) {
42 size_t TestOrderablePendingTask::task_id_counter = 0;
44 TestOrderablePendingTask::~TestOrderablePendingTask() {
47 bool TestOrderablePendingTask::operator==(
48 const TestOrderablePendingTask& other) const {
49 return task_id_ == other.task_id_;
52 bool TestOrderablePendingTask::operator<(
53 const TestOrderablePendingTask& other) const {
57 if (GetTimeToRun() == other.GetTimeToRun()) {
58 return task_id_ < other.task_id_;
60 return ShouldRunBefore(other);
63 scoped_refptr<base::debug::ConvertableToTraceFormat>
64 TestOrderablePendingTask::AsValue() const {
65 scoped_refptr<base::debug::TracedValue> state =
66 new base::debug::TracedValue();
67 AsValueInto(state.get());
71 void TestOrderablePendingTask::AsValueInto(
72 base::debug::TracedValue* state) const {
73 state->SetInteger("id", task_id_);
74 state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
75 state->SetString("posted_from", location.ToString());
78 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner()
80 now_src_(TestNowSource::Create(0)),
81 inside_run_tasks_until_(false) {
84 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner(
85 scoped_refptr<TestNowSource> now_src,
87 : advance_now_(advance_now),
89 max_tasks_(kAbsoluteMaxTasks),
90 inside_run_tasks_until_(false) {
93 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {}
95 // base::TestSimpleTaskRunner implementation
96 bool OrderedSimpleTaskRunner::PostDelayedTask(
97 const tracked_objects::Location& from_here,
98 const base::Closure& task,
99 base::TimeDelta delay) {
100 DCHECK(thread_checker_.CalledOnValidThread());
101 TestOrderablePendingTask pt(
102 from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE);
104 TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt);
105 pending_tasks_.insert(pt);
109 bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask(
110 const tracked_objects::Location& from_here,
111 const base::Closure& task,
112 base::TimeDelta delay) {
113 DCHECK(thread_checker_.CalledOnValidThread());
114 TestOrderablePendingTask pt(from_here,
118 base::TestPendingTask::NON_NESTABLE);
120 TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt);
121 pending_tasks_.insert(pt);
125 bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const {
126 DCHECK(thread_checker_.CalledOnValidThread());
130 base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() {
131 if (pending_tasks_.size() <= 0) {
132 return TestNowSource::kAbsoluteMaxNow;
135 return pending_tasks_.begin()->GetTimeToRun();
138 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() {
139 DCHECK(thread_checker_.CalledOnValidThread());
141 if (pending_tasks_.size() <= 0) {
142 return TestNowSource::kAbsoluteMaxNow - base::TimeTicks();
145 base::TimeDelta delay = NextTaskTime() - now_src_->Now();
146 if (delay > base::TimeDelta())
148 return base::TimeDelta();
151 const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks =
152 std::numeric_limits<size_t>::max();
154 bool OrderedSimpleTaskRunner::RunTasksWhile(
155 base::Callback<bool(void)> condition) {
156 std::vector<base::Callback<bool(void)> > conditions(1);
157 conditions[0] = condition;
158 return RunTasksWhile(conditions);
161 bool OrderedSimpleTaskRunner::RunTasksWhile(
162 const std::vector<base::Callback<bool(void)> >& conditions) {
164 "OrderedSimpleTaskRunner::RunPendingTasks",
168 inside_run_tasks_until_);
169 DCHECK(thread_checker_.CalledOnValidThread());
171 if (inside_run_tasks_until_)
174 base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_,
177 // Make a copy so we can append some extra run checks.
178 std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions);
180 // Provide a timeout base on number of tasks run so this doesn't loop
182 modifiable_conditions.push_back(TaskRunCountBelow(max_tasks_));
184 // If to advance now or not
186 modifiable_conditions.push_back(NowBefore(now_src_->Now()));
188 modifiable_conditions.push_back(AdvanceNow());
191 while (pending_tasks_.size() > 0) {
192 // Check if we should continue to run pending tasks.
193 bool condition_success = true;
194 for (std::vector<base::Callback<bool(void)> >::iterator it =
195 modifiable_conditions.begin();
196 it != modifiable_conditions.end();
198 condition_success = it->Run();
199 if (!condition_success)
203 // Conditions could modify the pending task length, so we need to recheck
204 // that there are tasks to run.
205 if (!condition_success || pending_tasks_.size() == 0) {
209 std::set<TestOrderablePendingTask>::iterator task_to_run =
210 pending_tasks_.begin();
213 "OrderedSimpleTaskRunner::RunPendingTasks running",
215 task_to_run->AsValue());
216 task_to_run->task.Run();
219 pending_tasks_.erase(task_to_run);
222 return pending_tasks_.size() > 0;
225 bool OrderedSimpleTaskRunner::RunPendingTasks() {
226 return RunTasksWhile(TaskExistedInitially());
229 bool OrderedSimpleTaskRunner::RunUntilIdle() {
230 return RunTasksWhile(std::vector<base::Callback<bool(void)> >());
233 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) {
234 // If we are not auto advancing, force now forward to the time.
235 if (!advance_now_ && now_src_->Now() < time)
236 now_src_->SetNow(time);
239 bool result = RunTasksWhile(NowBefore(time));
241 // If the next task is after the stopping time and auto-advancing now, then
242 // force time to be the stopping time.
243 if (!result && advance_now_ && now_src_->Now() < time) {
244 now_src_->SetNow(time);
250 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) {
251 return RunUntilTime(now_src_->Now() + period);
254 // base::debug tracing functionality
255 scoped_refptr<base::debug::ConvertableToTraceFormat>
256 OrderedSimpleTaskRunner::AsValue() const {
257 scoped_refptr<base::debug::TracedValue> state =
258 new base::debug::TracedValue();
259 AsValueInto(state.get());
263 void OrderedSimpleTaskRunner::AsValueInto(
264 base::debug::TracedValue* state) const {
265 state->SetInteger("pending_tasks", pending_tasks_.size());
266 for (std::set<TestOrderablePendingTask>::const_iterator it =
267 pending_tasks_.begin();
268 it != pending_tasks_.end();
270 state->BeginDictionary(
271 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str());
272 it->AsValueInto(state);
273 state->EndDictionary();
275 now_src_->AsValueInto(state);
278 base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow(
280 return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback,
282 base::Owned(new size_t(0)));
285 bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks,
287 return (*tasks_run)++ < max_tasks;
290 base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() {
291 // base::Bind takes a copy of pending_tasks_
292 return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback,
293 base::Unretained(this),
297 bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback(
298 const std::set<TestOrderablePendingTask>& existing_tasks) {
299 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end();
302 base::Callback<bool(void)> OrderedSimpleTaskRunner::NowBefore(
303 base::TimeTicks stop_at) {
304 return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback,
305 base::Unretained(this),
308 bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at) {
309 return NextTaskTime() <= stop_at;
312 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() {
313 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback,
314 base::Unretained(this));
317 bool OrderedSimpleTaskRunner::AdvanceNowCallback() {
318 base::TimeTicks next_task_time = NextTaskTime();
319 if (now_src_->Now() < next_task_time) {
320 now_src_->SetNow(next_task_time);