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/numerics/safe_conversions.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/trace_event/trace_event.h"
17 #include "base/trace_event/trace_event_argument.h"
19 #define TRACE_TASK(function, task) \
20 TRACE_EVENT_INSTANT1( \
21 "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue());
23 #define TRACE_TASK_RUN(function, tag, task)
27 // TestOrderablePendingTask implementation
28 TestOrderablePendingTask::TestOrderablePendingTask()
29 : base::TestPendingTask(),
30 task_id_(TestOrderablePendingTask::task_id_counter
++) {
33 TestOrderablePendingTask::TestOrderablePendingTask(
34 const tracked_objects::Location
& location
,
35 const base::Closure
& task
,
36 base::TimeTicks post_time
,
37 base::TimeDelta delay
,
38 TestNestability nestability
)
39 : base::TestPendingTask(location
, task
, post_time
, delay
, nestability
),
40 task_id_(TestOrderablePendingTask::task_id_counter
++) {
43 size_t TestOrderablePendingTask::task_id_counter
= 0;
45 TestOrderablePendingTask::~TestOrderablePendingTask() {
48 bool TestOrderablePendingTask::operator==(
49 const TestOrderablePendingTask
& other
) const {
50 return task_id_
== other
.task_id_
;
53 bool TestOrderablePendingTask::operator<(
54 const TestOrderablePendingTask
& other
) const {
58 if (GetTimeToRun() == other
.GetTimeToRun()) {
59 return task_id_
< other
.task_id_
;
61 return ShouldRunBefore(other
);
64 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
65 TestOrderablePendingTask::AsValue() const {
66 scoped_refptr
<base::trace_event::TracedValue
> state
=
67 new base::trace_event::TracedValue();
68 AsValueInto(state
.get());
72 void TestOrderablePendingTask::AsValueInto(
73 base::trace_event::TracedValue
* state
) const {
74 state
->SetInteger("id", base::saturated_cast
<int>(task_id_
));
75 state
->SetInteger("run_at", GetTimeToRun().ToInternalValue());
76 state
->SetString("posted_from", location
.ToString());
79 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner(
80 base::SimpleTestTickClock
* now_src
,
82 : advance_now_(advance_now
),
84 max_tasks_(kAbsoluteMaxTasks
),
85 inside_run_tasks_until_(false) {
88 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {}
91 base::TimeTicks
OrderedSimpleTaskRunner::AbsoluteMaxNow() {
92 return base::TimeTicks::FromInternalValue(
93 std::numeric_limits
<int64_t>::max());
96 // base::TestSimpleTaskRunner implementation
97 bool OrderedSimpleTaskRunner::PostDelayedTask(
98 const tracked_objects::Location
& from_here
,
99 const base::Closure
& task
,
100 base::TimeDelta delay
) {
101 DCHECK(thread_checker_
.CalledOnValidThread());
102 TestOrderablePendingTask
pt(from_here
, task
, now_src_
->NowTicks(), delay
,
103 base::TestPendingTask::NESTABLE
);
105 TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt
);
106 pending_tasks_
.insert(pt
);
110 bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask(
111 const tracked_objects::Location
& from_here
,
112 const base::Closure
& task
,
113 base::TimeDelta delay
) {
114 DCHECK(thread_checker_
.CalledOnValidThread());
115 TestOrderablePendingTask
pt(from_here
, task
, now_src_
->NowTicks(), delay
,
116 base::TestPendingTask::NON_NESTABLE
);
118 TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt
);
119 pending_tasks_
.insert(pt
);
123 bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const {
124 DCHECK(thread_checker_
.CalledOnValidThread());
128 size_t OrderedSimpleTaskRunner::NumPendingTasks() const {
129 return pending_tasks_
.size();
132 bool OrderedSimpleTaskRunner::HasPendingTasks() const {
133 return pending_tasks_
.size() > 0;
136 base::TimeTicks
OrderedSimpleTaskRunner::NextTaskTime() {
137 if (pending_tasks_
.size() <= 0) {
138 return AbsoluteMaxNow();
141 return pending_tasks_
.begin()->GetTimeToRun();
144 base::TimeDelta
OrderedSimpleTaskRunner::DelayToNextTaskTime() {
145 DCHECK(thread_checker_
.CalledOnValidThread());
147 if (pending_tasks_
.size() <= 0) {
148 return AbsoluteMaxNow() - base::TimeTicks();
151 base::TimeDelta delay
= NextTaskTime() - now_src_
->NowTicks();
152 if (delay
> base::TimeDelta())
154 return base::TimeDelta();
157 const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks
=
158 std::numeric_limits
<size_t>::max();
160 bool OrderedSimpleTaskRunner::RunTasksWhile(
161 base::Callback
<bool(void)> condition
) {
162 std::vector
<base::Callback
<bool(void)>> conditions(1);
163 conditions
[0] = condition
;
164 return RunTasksWhile(conditions
);
167 bool OrderedSimpleTaskRunner::RunTasksWhile(
168 const std::vector
<base::Callback
<bool(void)>>& conditions
) {
170 "OrderedSimpleTaskRunner::RunPendingTasks",
174 inside_run_tasks_until_
);
175 DCHECK(thread_checker_
.CalledOnValidThread());
177 if (inside_run_tasks_until_
)
180 base::AutoReset
<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_
,
183 // Make a copy so we can append some extra run checks.
184 std::vector
<base::Callback
<bool(void)>> modifiable_conditions(conditions
);
186 // Provide a timeout base on number of tasks run so this doesn't loop
188 modifiable_conditions
.push_back(TaskRunCountBelow(max_tasks_
));
190 // If to advance now or not
192 modifiable_conditions
.push_back(NowBefore(now_src_
->NowTicks()));
194 modifiable_conditions
.push_back(AdvanceNow());
197 while (pending_tasks_
.size() > 0) {
198 // Check if we should continue to run pending tasks.
199 bool condition_success
= true;
200 for (std::vector
<base::Callback
<bool(void)>>::iterator it
=
201 modifiable_conditions
.begin();
202 it
!= modifiable_conditions
.end();
204 condition_success
= it
->Run();
205 if (!condition_success
)
209 // Conditions could modify the pending task length, so we need to recheck
210 // that there are tasks to run.
211 if (!condition_success
|| !HasPendingTasks()) {
215 std::set
<TestOrderablePendingTask
>::iterator task_to_run
=
216 pending_tasks_
.begin();
219 "OrderedSimpleTaskRunner::RunPendingTasks running",
221 task_to_run
->AsValue());
222 task_to_run
->task
.Run();
225 pending_tasks_
.erase(task_to_run
);
228 return HasPendingTasks();
231 bool OrderedSimpleTaskRunner::RunPendingTasks() {
232 return RunTasksWhile(TaskExistedInitially());
235 bool OrderedSimpleTaskRunner::RunUntilIdle() {
236 return RunTasksWhile(std::vector
<base::Callback
<bool(void)>>());
239 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time
) {
240 // If we are not auto advancing, force now forward to the time.
241 if (!advance_now_
&& now_src_
->NowTicks() < time
)
242 now_src_
->Advance(time
- now_src_
->NowTicks());
245 bool result
= RunTasksWhile(NowBefore(time
));
247 // If the next task is after the stopping time and auto-advancing now, then
248 // force time to be the stopping time.
249 if (!result
&& advance_now_
&& now_src_
->NowTicks() < time
) {
250 now_src_
->Advance(time
- now_src_
->NowTicks());
256 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period
) {
257 return RunUntilTime(now_src_
->NowTicks() + period
);
260 // base::trace_event tracing functionality
261 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
262 OrderedSimpleTaskRunner::AsValue() const {
263 scoped_refptr
<base::trace_event::TracedValue
> state
=
264 new base::trace_event::TracedValue();
265 AsValueInto(state
.get());
269 void OrderedSimpleTaskRunner::AsValueInto(
270 base::trace_event::TracedValue
* state
) const {
271 state
->SetInteger("pending_tasks",
272 base::saturated_cast
<int>(pending_tasks_
.size()));
274 state
->BeginArray("tasks");
275 for (std::set
<TestOrderablePendingTask
>::const_iterator it
=
276 pending_tasks_
.begin();
277 it
!= pending_tasks_
.end();
279 state
->BeginDictionary();
280 it
->AsValueInto(state
);
281 state
->EndDictionary();
285 state
->BeginDictionary("now_src");
286 state
->SetDouble("now_in_ms", (now_src_
->NowTicks() - base::TimeTicks())
288 state
->EndDictionary();
290 state
->SetBoolean("advance_now", advance_now_
);
291 state
->SetBoolean("inside_run_tasks_until", inside_run_tasks_until_
);
292 state
->SetString("max_tasks", base::SizeTToString(max_tasks_
));
295 base::Callback
<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow(
297 return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback
,
299 base::Owned(new size_t(0)));
302 bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks
,
304 return (*tasks_run
)++ < max_tasks
;
307 base::Callback
<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() {
308 // base::Bind takes a copy of pending_tasks_
309 return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback
,
310 base::Unretained(this),
314 bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback(
315 const std::set
<TestOrderablePendingTask
>& existing_tasks
) {
316 return existing_tasks
.find(*pending_tasks_
.begin()) != existing_tasks
.end();
319 base::Callback
<bool(void)> OrderedSimpleTaskRunner::NowBefore(
320 base::TimeTicks stop_at
) {
321 return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback
,
322 base::Unretained(this),
325 bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at
) {
326 return NextTaskTime() <= stop_at
;
329 base::Callback
<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() {
330 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback
,
331 base::Unretained(this));
334 bool OrderedSimpleTaskRunner::AdvanceNowCallback() {
335 base::TimeTicks next_task_time
= NextTaskTime();
336 if (now_src_
->NowTicks() < next_task_time
) {
337 now_src_
->Advance(next_task_time
- now_src_
->NowTicks());