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/strings/string_number_conversions.h"
15 #include "base/trace_event/trace_event.h"
16 #include "base/trace_event/trace_event_argument.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::trace_event::ConvertableToTraceFormat
>
64 TestOrderablePendingTask::AsValue() const {
65 scoped_refptr
<base::trace_event::TracedValue
> state
=
66 new base::trace_event::TracedValue();
67 AsValueInto(state
.get());
71 void TestOrderablePendingTask::AsValueInto(
72 base::trace_event::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 size_t OrderedSimpleTaskRunner::NumPendingTasks() const {
131 return pending_tasks_
.size();
134 bool OrderedSimpleTaskRunner::HasPendingTasks() const {
135 return pending_tasks_
.size() > 0;
138 base::TimeTicks
OrderedSimpleTaskRunner::NextTaskTime() {
139 if (pending_tasks_
.size() <= 0) {
140 return TestNowSource::kAbsoluteMaxNow
;
143 return pending_tasks_
.begin()->GetTimeToRun();
146 base::TimeDelta
OrderedSimpleTaskRunner::DelayToNextTaskTime() {
147 DCHECK(thread_checker_
.CalledOnValidThread());
149 if (pending_tasks_
.size() <= 0) {
150 return TestNowSource::kAbsoluteMaxNow
- base::TimeTicks();
153 base::TimeDelta delay
= NextTaskTime() - now_src_
->Now();
154 if (delay
> base::TimeDelta())
156 return base::TimeDelta();
159 const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks
=
160 std::numeric_limits
<size_t>::max();
162 bool OrderedSimpleTaskRunner::RunTasksWhile(
163 base::Callback
<bool(void)> condition
) {
164 std::vector
<base::Callback
<bool(void)>> conditions(1);
165 conditions
[0] = condition
;
166 return RunTasksWhile(conditions
);
169 bool OrderedSimpleTaskRunner::RunTasksWhile(
170 const std::vector
<base::Callback
<bool(void)>>& conditions
) {
172 "OrderedSimpleTaskRunner::RunPendingTasks",
176 inside_run_tasks_until_
);
177 DCHECK(thread_checker_
.CalledOnValidThread());
179 if (inside_run_tasks_until_
)
182 base::AutoReset
<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_
,
185 // Make a copy so we can append some extra run checks.
186 std::vector
<base::Callback
<bool(void)>> modifiable_conditions(conditions
);
188 // Provide a timeout base on number of tasks run so this doesn't loop
190 modifiable_conditions
.push_back(TaskRunCountBelow(max_tasks_
));
192 // If to advance now or not
194 modifiable_conditions
.push_back(NowBefore(now_src_
->Now()));
196 modifiable_conditions
.push_back(AdvanceNow());
199 while (pending_tasks_
.size() > 0) {
200 // Check if we should continue to run pending tasks.
201 bool condition_success
= true;
202 for (std::vector
<base::Callback
<bool(void)>>::iterator it
=
203 modifiable_conditions
.begin();
204 it
!= modifiable_conditions
.end();
206 condition_success
= it
->Run();
207 if (!condition_success
)
211 // Conditions could modify the pending task length, so we need to recheck
212 // that there are tasks to run.
213 if (!condition_success
|| !HasPendingTasks()) {
217 std::set
<TestOrderablePendingTask
>::iterator task_to_run
=
218 pending_tasks_
.begin();
221 "OrderedSimpleTaskRunner::RunPendingTasks running",
223 task_to_run
->AsValue());
224 task_to_run
->task
.Run();
227 pending_tasks_
.erase(task_to_run
);
230 return HasPendingTasks();
233 bool OrderedSimpleTaskRunner::RunPendingTasks() {
234 return RunTasksWhile(TaskExistedInitially());
237 bool OrderedSimpleTaskRunner::RunUntilIdle() {
238 return RunTasksWhile(std::vector
<base::Callback
<bool(void)>>());
241 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time
) {
242 // If we are not auto advancing, force now forward to the time.
243 if (!advance_now_
&& now_src_
->Now() < time
)
244 now_src_
->SetNow(time
);
247 bool result
= RunTasksWhile(NowBefore(time
));
249 // If the next task is after the stopping time and auto-advancing now, then
250 // force time to be the stopping time.
251 if (!result
&& advance_now_
&& now_src_
->Now() < time
) {
252 now_src_
->SetNow(time
);
258 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period
) {
259 return RunUntilTime(now_src_
->Now() + period
);
262 // base::trace_event tracing functionality
263 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
264 OrderedSimpleTaskRunner::AsValue() const {
265 scoped_refptr
<base::trace_event::TracedValue
> state
=
266 new base::trace_event::TracedValue();
267 AsValueInto(state
.get());
271 void OrderedSimpleTaskRunner::AsValueInto(
272 base::trace_event::TracedValue
* state
) const {
273 state
->SetInteger("pending_tasks", pending_tasks_
.size());
275 state
->BeginArray("tasks");
276 for (std::set
<TestOrderablePendingTask
>::const_iterator it
=
277 pending_tasks_
.begin();
278 it
!= pending_tasks_
.end();
280 state
->BeginDictionary();
281 it
->AsValueInto(state
);
282 state
->EndDictionary();
286 state
->BeginDictionary("now_src");
287 now_src_
->AsValueInto(state
);
288 state
->EndDictionary();
291 base::Callback
<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow(
293 return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback
,
295 base::Owned(new size_t(0)));
298 bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks
,
300 return (*tasks_run
)++ < max_tasks
;
303 base::Callback
<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() {
304 // base::Bind takes a copy of pending_tasks_
305 return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback
,
306 base::Unretained(this),
310 bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback(
311 const std::set
<TestOrderablePendingTask
>& existing_tasks
) {
312 return existing_tasks
.find(*pending_tasks_
.begin()) != existing_tasks
.end();
315 base::Callback
<bool(void)> OrderedSimpleTaskRunner::NowBefore(
316 base::TimeTicks stop_at
) {
317 return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback
,
318 base::Unretained(this),
321 bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at
) {
322 return NextTaskTime() <= stop_at
;
325 base::Callback
<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() {
326 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback
,
327 base::Unretained(this));
330 bool OrderedSimpleTaskRunner::AdvanceNowCallback() {
331 base::TimeTicks next_task_time
= NextTaskTime();
332 if (now_src_
->Now() < next_task_time
) {
333 now_src_
->SetNow(next_task_time
);