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.get()); | |
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::RunTasksWhile( | |
155 base::Callback<bool(void)> condition) { | |
156 std::vector<base::Callback<bool(void)> > conditions(1); | |
157 conditions[0] = condition; | |
158 return RunTasksWhile(conditions); | |
159 } | |
160 | |
161 bool OrderedSimpleTaskRunner::RunTasksWhile( | |
162 const std::vector<base::Callback<bool(void)> >& conditions) { | |
163 TRACE_EVENT2("cc", | |
164 "OrderedSimpleTaskRunner::RunPendingTasks", | |
165 "this", | |
166 AsValue(), | |
167 "nested", | |
168 inside_run_tasks_until_); | |
169 DCHECK(thread_checker_.CalledOnValidThread()); | |
170 | |
171 if (inside_run_tasks_until_) | |
172 return true; | |
173 | |
174 base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_, | |
175 true); | |
176 | |
177 // Make a copy so we can append some extra run checks. | |
178 std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions); | |
179 | |
180 // Provide a timeout base on number of tasks run so this doesn't loop | |
181 // forever. | |
182 modifiable_conditions.push_back(TaskRunCountBelow(max_tasks_)); | |
183 | |
184 // If to advance now or not | |
185 if (!advance_now_) { | |
186 modifiable_conditions.push_back(NowBefore(now_src_->Now())); | |
187 } else { | |
188 modifiable_conditions.push_back(AdvanceNow()); | |
189 } | |
190 | |
191 while (pending_tasks_.size() > 0) { | |
192 // Check if we should continue to run pending tasks | |
193 for (std::vector<base::Callback<bool(void)> >::iterator it = | |
194 modifiable_conditions.begin(); | |
195 it != modifiable_conditions.end(); | |
196 it++) { | |
197 if (!it->Run()) { | |
198 return pending_tasks_.size() > 0; | |
199 } | |
200 } | |
201 | |
202 std::set<TestOrderablePendingTask>::iterator task_to_run = | |
203 pending_tasks_.begin(); | |
204 { | |
205 TRACE_EVENT1("cc", | |
206 "OrderedSimpleTaskRunner::RunPendingTasks running", | |
207 "task", | |
208 task_to_run->AsValue()); | |
209 task_to_run->task.Run(); | |
210 } | |
211 | |
212 pending_tasks_.erase(task_to_run); | |
213 } | |
214 | |
215 return false; | |
216 } | |
217 | |
218 bool OrderedSimpleTaskRunner::RunPendingTasks() { | |
219 return RunTasksWhile(TaskExistedInitially()); | |
220 } | |
221 | |
222 bool OrderedSimpleTaskRunner::RunUntilIdle() { | |
223 return RunTasksWhile(std::vector<base::Callback<bool(void)> >()); | |
224 } | |
225 | |
226 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { | |
227 // If we are not auto advancing, force now forward to the time. | |
228 if (!advance_now_ && now_src_->Now() < time) | |
229 now_src_->SetNow(time); | |
230 | |
231 // Run tasks | |
232 bool result = RunTasksWhile(NowBefore(time)); | |
233 | |
234 // If the next task is after the stopping time and auto-advancing now, then | |
235 // force time to be the stopping time. | |
236 if (!result && advance_now_ && now_src_->Now() < time) { | |
237 now_src_->SetNow(time); | |
238 } | |
239 | |
240 return result; | |
241 } | |
242 | |
243 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { | |
244 return RunUntilTime(now_src_->Now() + period); | |
245 } | |
246 | |
247 // base::debug tracing functionality | |
248 scoped_refptr<base::debug::ConvertableToTraceFormat> | |
249 OrderedSimpleTaskRunner::AsValue() const { | |
250 scoped_refptr<base::debug::TracedValue> state = | |
251 new base::debug::TracedValue(); | |
252 AsValueInto(state.get()); | |
253 return state; | |
254 } | |
255 | |
256 void OrderedSimpleTaskRunner::AsValueInto( | |
257 base::debug::TracedValue* state) const { | |
258 state->SetInteger("pending_tasks", pending_tasks_.size()); | |
259 for (std::set<TestOrderablePendingTask>::const_iterator it = | |
260 pending_tasks_.begin(); | |
261 it != pending_tasks_.end(); | |
262 ++it) { | |
263 state->BeginDictionary( | |
264 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); | |
265 it->AsValueInto(state); | |
266 state->EndDictionary(); | |
267 } | |
268 now_src_->AsValueInto(state); | |
269 } | |
270 | |
271 base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow( | |
272 size_t max_tasks) { | |
273 return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback, | |
274 base::Unretained(this), | |
275 max_tasks, | |
276 base::Owned(new size_t(0))); | |
277 } | |
278 | |
279 bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks, | |
brianderson
2014/09/08 19:24:08
Looks like this can be static.
mithro-old
2014/09/09 02:39:45
Done.
| |
280 size_t* tasks_run) { | |
281 return (*tasks_run)++ < max_tasks; | |
282 } | |
283 | |
284 base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() { | |
285 // base::Bind takes a copy of pending_tasks_ | |
286 return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback, | |
287 base::Unretained(this), | |
288 pending_tasks_); | |
289 } | |
290 | |
291 bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback( | |
292 const std::set<TestOrderablePendingTask>& existing_tasks) { | |
293 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); | |
294 } | |
295 | |
296 base::Callback<bool(void)> OrderedSimpleTaskRunner::NowBefore( | |
297 base::TimeTicks stop_at) { | |
298 return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback, | |
299 base::Unretained(this), | |
300 stop_at); | |
301 } | |
302 bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at) { | |
303 return NextTaskTime() <= stop_at; | |
304 } | |
305 | |
306 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { | |
307 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, | |
308 base::Unretained(this)); | |
309 } | |
310 | |
311 bool OrderedSimpleTaskRunner::AdvanceNowCallback() { | |
312 base::TimeTicks next_task_time = NextTaskTime(); | |
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 |