OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/test/ordered_simple_task_runner.h" | 5 #include "cc/test/ordered_simple_task_runner.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <limits> |
8 #include <deque> | 8 #include <set> |
9 | 9 #include <sstream> |
10 #include "base/logging.h" | 10 #include <string> |
11 | 11 #include <vector> |
12 namespace { | 12 |
13 | 13 #include "base/auto_reset.h" |
14 bool TestPendingTaskComparator(const base::TestPendingTask& lhs, | 14 #include "base/debug/trace_event.h" |
15 const base::TestPendingTask& rhs) { | 15 #include "base/debug/trace_event_argument.h" |
16 return lhs.ShouldRunBefore(rhs); | 16 #include "base/strings/string_number_conversions.h" |
17 } | 17 |
18 | 18 #define TRACE_TASK(function, task) \ |
19 } | 19 TRACE_EVENT_INSTANT1( \ |
20 "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue()); | |
21 | |
22 #define TRACE_TASK_RUN(function, tag, task) | |
20 | 23 |
21 namespace cc { | 24 namespace cc { |
22 | 25 |
23 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() {} | 26 // TestOrderablePendingTask implementation |
27 TestOrderablePendingTask::TestOrderablePendingTask() | |
28 : base::TestPendingTask(), | |
29 task_id_(TestOrderablePendingTask::task_id_counter++) { | |
30 } | |
31 | |
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++) { | |
40 } | |
41 | |
42 size_t TestOrderablePendingTask::task_id_counter = 0; | |
43 | |
44 TestOrderablePendingTask::~TestOrderablePendingTask() { | |
45 } | |
46 | |
47 bool TestOrderablePendingTask::operator==( | |
48 const TestOrderablePendingTask& other) const { | |
49 return task_id_ == other.task_id_; | |
50 } | |
51 | |
52 bool TestOrderablePendingTask::operator<( | |
53 const TestOrderablePendingTask& other) const { | |
54 if (*this == other) | |
55 return false; | |
56 | |
57 if (GetTimeToRun() == other.GetTimeToRun()) { | |
58 return task_id_ < other.task_id_; | |
59 } | |
60 return ShouldRunBefore(other); | |
61 } | |
62 | |
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); | |
68 return state; | |
69 } | |
70 | |
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()); | |
76 } | |
77 | |
78 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() | |
79 : advance_now_(true), | |
80 now_src_(TestNowSource::Create(0)), | |
81 inside_run_tasks_until_(false) { | |
82 } | |
83 | |
84 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner( | |
85 scoped_refptr<TestNowSource> now_src, | |
86 bool advance_now) | |
87 : advance_now_(advance_now), | |
88 now_src_(now_src), | |
89 max_tasks_(kAbsoluteMaxTasks), | |
90 inside_run_tasks_until_(false) { | |
91 } | |
24 | 92 |
25 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} | 93 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} |
26 | 94 |
27 void OrderedSimpleTaskRunner::RunPendingTasks() { | 95 // base::TestSimpleTaskRunner implementation |
28 DCHECK(thread_checker_.CalledOnValidThread()); | 96 bool OrderedSimpleTaskRunner::PostDelayedTask( |
29 // Swap with a local variable to avoid re-entrancy problems. | 97 const tracked_objects::Location& from_here, |
30 std::deque<base::TestPendingTask> tasks_to_run; | 98 const base::Closure& task, |
31 tasks_to_run.swap(pending_tasks_); | 99 base::TimeDelta delay) { |
32 std::stable_sort(tasks_to_run.begin(), | 100 DCHECK(thread_checker_.CalledOnValidThread()); |
33 tasks_to_run.end(), | 101 TestOrderablePendingTask pt( |
34 TestPendingTaskComparator); | 102 from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE); |
35 for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); | 103 |
36 it != tasks_to_run.end(); ++it) { | 104 TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt); |
37 it->task.Run(); | 105 pending_tasks_.insert(pt); |
38 } | 106 return true; |
107 } | |
108 | |
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, | |
115 task, | |
116 now_src_->Now(), | |
117 delay, | |
118 base::TestPendingTask::NON_NESTABLE); | |
119 | |
120 TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt); | |
121 pending_tasks_.insert(pt); | |
122 return true; | |
123 } | |
124 | |
125 bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const { | |
126 DCHECK(thread_checker_.CalledOnValidThread()); | |
127 return true; | |
128 } | |
129 | |
130 base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() { | |
131 if (pending_tasks_.size() <= 0) { | |
132 return TestNowSource::kAbsoluteMaxNow; | |
133 } | |
134 | |
135 return pending_tasks_.begin()->GetTimeToRun(); | |
136 } | |
137 | |
138 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() { | |
139 DCHECK(thread_checker_.CalledOnValidThread()); | |
140 | |
141 if (pending_tasks_.size() <= 0) { | |
142 return TestNowSource::kAbsoluteMaxNow - base::TimeTicks(); | |
143 } | |
144 | |
145 base::TimeDelta delay = NextTaskTime() - now_src_->Now(); | |
146 if (delay > base::TimeDelta()) | |
147 return delay; | |
148 return base::TimeDelta(); | |
149 } | |
150 | |
151 const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks = | |
152 std::numeric_limits<size_t>::max(); | |
153 | |
154 bool OrderedSimpleTaskRunner::RunTasks(base::Callback<bool(void)> condition) { | |
155 std::vector<base::Callback<bool(void)> > conditions(1); | |
156 conditions[0] = condition; | |
157 return RunTasks(conditions); | |
158 } | |
159 | |
160 bool OrderedSimpleTaskRunner::RunTasks( | |
161 const std::vector<base::Callback<bool(void)> >& conditions) { | |
162 TRACE_EVENT1( | |
163 "cc", "OrderedSimpleTaskRunner::RunPendingTasks", "this", AsValue()); | |
164 DCHECK(thread_checker_.CalledOnValidThread()); | |
165 | |
166 // Make a copy so we can append some extra run checks. | |
167 std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions); | |
168 | |
169 // Provide a timeout base on number of tasks run so this doesn't loop | |
170 // forever. | |
171 modifiable_conditions.push_back(WhileTaskRunCountBelow(max_tasks_)); | |
172 | |
173 // If to advance now or not | |
174 if (!advance_now_) { | |
175 modifiable_conditions.push_back(WhileNowBefore(now_src_->Now())); | |
176 } else { | |
177 modifiable_conditions.push_back(AdvanceNow()); | |
178 } | |
179 | |
180 if (inside_run_tasks_until_) | |
brianderson
2014/09/05 02:48:03
Should this early out and the AutoReset move up?
mithro-old
2014/09/08 12:52:19
Done.
| |
181 return true; | |
182 | |
183 base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_, | |
184 true); | |
185 while (pending_tasks_.size() > 0) { | |
186 // Check if we should continue to run pending tasks | |
187 for (std::vector<base::Callback<bool(void)> >::iterator it = | |
188 modifiable_conditions.begin(); | |
189 it != modifiable_conditions.end(); | |
190 it++) { | |
191 if (!it->Run()) { | |
192 return pending_tasks_.size() > 0; | |
brianderson
2014/09/05 02:48:03
Can you just return true here?
mithro-old
2014/09/08 12:52:19
A condition could possibly modify the queue size a
brianderson
2014/09/08 19:24:08
A comment explaining that a condition might modify
mithro-old
2014/09/09 02:39:44
Done.
| |
193 } | |
194 } | |
195 | |
196 std::set<TestOrderablePendingTask>::iterator task_to_run = | |
197 pending_tasks_.begin(); | |
198 { | |
199 TRACE_EVENT1("cc", | |
200 "OrderedSimpleTaskRunner::RunPendingTasks running", | |
201 "task", | |
202 task_to_run->AsValue()); | |
203 task_to_run->task.Run(); | |
204 } | |
205 | |
206 pending_tasks_.erase(task_to_run); | |
207 } | |
208 | |
209 return false; | |
210 } | |
211 | |
212 bool OrderedSimpleTaskRunner::RunPendingTasks() { | |
213 return RunTasks(WhileTaskExistedInitially()); | |
214 } | |
215 | |
216 bool OrderedSimpleTaskRunner::RunUntilIdle() { | |
217 return RunTasks(std::vector<base::Callback<bool(void)> >()); | |
218 } | |
219 | |
220 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { | |
221 // If we are not auto advancing, force now forward to the time. | |
222 if (!advance_now_ && now_src_->Now() < time) | |
223 now_src_->SetNow(time); | |
224 | |
225 // Run tasks | |
226 bool result = RunTasks(WhileNowBefore(time)); | |
227 | |
228 // If the next task is after the stopping time and auto-advancing now, then | |
229 // force time to be the stopping time. | |
230 if (!result && advance_now_ && now_src_->Now() < time) { | |
231 now_src_->SetNow(time); | |
232 } | |
233 | |
234 return result; | |
235 } | |
236 | |
237 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { | |
238 return RunUntilTime(now_src_->Now() + period); | |
239 } | |
240 | |
241 // base::debug tracing functionality | |
242 scoped_refptr<base::debug::ConvertableToTraceFormat> | |
243 OrderedSimpleTaskRunner::AsValue() const { | |
244 scoped_refptr<base::debug::TracedValue> state = | |
245 new base::debug::TracedValue(); | |
246 AsValueInto(state); | |
247 return state; | |
248 } | |
249 | |
250 void OrderedSimpleTaskRunner::AsValueInto( | |
251 base::debug::TracedValue* state) const { | |
252 state->SetInteger("pending_tasks", pending_tasks_.size()); | |
253 for (std::set<TestOrderablePendingTask>::const_iterator it = | |
254 pending_tasks_.begin(); | |
255 it != pending_tasks_.end(); | |
256 ++it) { | |
257 state->BeginDictionary( | |
258 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); | |
259 it->AsValueInto(state); | |
260 state->EndDictionary(); | |
261 } | |
262 now_src_->AsValueInto(state); | |
263 } | |
264 | |
265 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileTaskRunCountBelow( | |
266 size_t max_tasks) { | |
267 return base::Bind(&OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback, | |
268 base::Unretained(this), | |
269 max_tasks, | |
270 base::Owned(new size_t(0))); | |
271 } | |
272 | |
273 bool OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback( | |
274 size_t max_tasks, | |
275 size_t* tasks_run) { | |
276 return (*tasks_run)++ < max_tasks; | |
277 } | |
278 | |
279 base::Callback<bool(void)> | |
280 OrderedSimpleTaskRunner::WhileTaskExistedInitially() { | |
281 // base::Bind takes a copy of pending_tasks_ | |
282 return base::Bind(&OrderedSimpleTaskRunner::WhileTaskExistedInitiallyCallback, | |
283 base::Unretained(this), | |
284 pending_tasks_); | |
285 } | |
286 | |
287 bool OrderedSimpleTaskRunner::WhileTaskExistedInitiallyCallback( | |
288 const std::set<TestOrderablePendingTask>& existing_tasks) { | |
289 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); | |
290 } | |
291 | |
292 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileNowBefore( | |
293 base::TimeTicks stop_at) { | |
294 return base::Bind(&OrderedSimpleTaskRunner::WhileNowBeforeCallback, | |
295 base::Unretained(this), | |
296 stop_at); | |
297 } | |
298 bool OrderedSimpleTaskRunner::WhileNowBeforeCallback(base::TimeTicks stop_at) { | |
299 return NextTaskTime() <= stop_at; | |
300 } | |
301 | |
302 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { | |
brianderson
2014/09/05 02:48:03
I would want to explictly disallow side-effects li
mithro-old
2014/09/08 12:52:19
We also need side-effects for the "WhileTaskRunCou
brianderson
2014/09/08 19:24:08
Argh, naming is hard. I can't think of any better
mithro-old
2014/09/09 02:39:44
Done.
| |
303 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, | |
304 base::Unretained(this)); | |
305 } | |
306 | |
307 bool OrderedSimpleTaskRunner::AdvanceNowCallback() { | |
308 base::TimeTicks next_task_time = NextTaskTime(); | |
309 if (now_src_->Now() == TestNowSource::kAbsoluteMaxNow || | |
310 next_task_time == TestNowSource::kAbsoluteMaxNow) | |
311 return false; | |
brianderson
2014/09/05 02:48:03
This "return false" seems redundant with the exist
mithro-old
2014/09/08 12:52:19
Removed.
| |
312 | |
313 if (now_src_->Now() < next_task_time) { | |
314 now_src_->SetNow(next_task_time); | |
315 } | |
316 return true; | |
39 } | 317 } |
40 | 318 |
41 } // namespace cc | 319 } // namespace cc |
OLD | NEW |