OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/test/ordered_simple_task_runner.h" | |
6 | |
7 #include <limits> | |
8 #include <set> | |
9 #include <sstream> | |
10 #include <string> | |
11 #include <vector> | |
12 | |
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" | |
17 | |
18 #define TRACE_TASK(function, task) \ | |
19 TRACE_EVENT_INSTANT1( \ | |
20 "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue()); | |
21 | |
22 #define TRACE_TASK_RUN(function, tag, task) | |
23 | |
24 namespace cc { | |
25 | |
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::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()); | |
68 return state; | |
69 } | |
70 | |
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()); | |
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 } | |
92 | |
93 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} | |
94 | |
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); | |
103 | |
104 TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt); | |
105 pending_tasks_.insert(pt); | |
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 size_t OrderedSimpleTaskRunner::NumPendingTasks() const { | |
131 return pending_tasks_.size(); | |
132 } | |
133 | |
134 bool OrderedSimpleTaskRunner::HasPendingTasks() const { | |
135 return pending_tasks_.size() > 0; | |
136 } | |
137 | |
138 base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() { | |
139 if (pending_tasks_.size() <= 0) { | |
140 return TestNowSource::kAbsoluteMaxNow; | |
141 } | |
142 | |
143 return pending_tasks_.begin()->GetTimeToRun(); | |
144 } | |
145 | |
146 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() { | |
147 DCHECK(thread_checker_.CalledOnValidThread()); | |
148 | |
149 if (pending_tasks_.size() <= 0) { | |
150 return TestNowSource::kAbsoluteMaxNow - base::TimeTicks(); | |
151 } | |
152 | |
153 base::TimeDelta delay = NextTaskTime() - now_src_->Now(); | |
154 if (delay > base::TimeDelta()) | |
155 return delay; | |
156 return base::TimeDelta(); | |
157 } | |
158 | |
159 const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks = | |
160 std::numeric_limits<size_t>::max(); | |
161 | |
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); | |
167 } | |
168 | |
169 bool OrderedSimpleTaskRunner::RunTasksWhile( | |
170 const std::vector<base::Callback<bool(void)>>& conditions) { | |
171 TRACE_EVENT2("cc", | |
172 "OrderedSimpleTaskRunner::RunPendingTasks", | |
173 "this", | |
174 AsValue(), | |
175 "nested", | |
176 inside_run_tasks_until_); | |
177 DCHECK(thread_checker_.CalledOnValidThread()); | |
178 | |
179 if (inside_run_tasks_until_) | |
180 return true; | |
181 | |
182 base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_, | |
183 true); | |
184 | |
185 // Make a copy so we can append some extra run checks. | |
186 std::vector<base::Callback<bool(void)>> modifiable_conditions(conditions); | |
187 | |
188 // Provide a timeout base on number of tasks run so this doesn't loop | |
189 // forever. | |
190 modifiable_conditions.push_back(TaskRunCountBelow(max_tasks_)); | |
191 | |
192 // If to advance now or not | |
193 if (!advance_now_) { | |
194 modifiable_conditions.push_back(NowBefore(now_src_->Now())); | |
195 } else { | |
196 modifiable_conditions.push_back(AdvanceNow()); | |
197 } | |
198 | |
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(); | |
205 it++) { | |
206 condition_success = it->Run(); | |
207 if (!condition_success) | |
208 break; | |
209 } | |
210 | |
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()) { | |
214 break; | |
215 } | |
216 | |
217 std::set<TestOrderablePendingTask>::iterator task_to_run = | |
218 pending_tasks_.begin(); | |
219 { | |
220 TRACE_EVENT1("cc", | |
221 "OrderedSimpleTaskRunner::RunPendingTasks running", | |
222 "task", | |
223 task_to_run->AsValue()); | |
224 task_to_run->task.Run(); | |
225 } | |
226 | |
227 pending_tasks_.erase(task_to_run); | |
228 } | |
229 | |
230 return HasPendingTasks(); | |
231 } | |
232 | |
233 bool OrderedSimpleTaskRunner::RunPendingTasks() { | |
234 return RunTasksWhile(TaskExistedInitially()); | |
235 } | |
236 | |
237 bool OrderedSimpleTaskRunner::RunUntilIdle() { | |
238 return RunTasksWhile(std::vector<base::Callback<bool(void)>>()); | |
239 } | |
240 | |
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); | |
245 | |
246 // Run tasks | |
247 bool result = RunTasksWhile(NowBefore(time)); | |
248 | |
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); | |
253 } | |
254 | |
255 return result; | |
256 } | |
257 | |
258 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { | |
259 return RunUntilTime(now_src_->Now() + period); | |
260 } | |
261 | |
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()); | |
268 return state; | |
269 } | |
270 | |
271 void OrderedSimpleTaskRunner::AsValueInto( | |
272 base::trace_event::TracedValue* state) const { | |
273 state->SetInteger("pending_tasks", pending_tasks_.size()); | |
274 | |
275 state->BeginArray("tasks"); | |
276 for (std::set<TestOrderablePendingTask>::const_iterator it = | |
277 pending_tasks_.begin(); | |
278 it != pending_tasks_.end(); | |
279 ++it) { | |
280 state->BeginDictionary(); | |
281 it->AsValueInto(state); | |
282 state->EndDictionary(); | |
283 } | |
284 state->EndArray(); | |
285 | |
286 state->BeginDictionary("now_src"); | |
287 now_src_->AsValueInto(state); | |
288 state->EndDictionary(); | |
289 } | |
290 | |
291 base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow( | |
292 size_t max_tasks) { | |
293 return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback, | |
294 max_tasks, | |
295 base::Owned(new size_t(0))); | |
296 } | |
297 | |
298 bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks, | |
299 size_t* tasks_run) { | |
300 return (*tasks_run)++ < max_tasks; | |
301 } | |
302 | |
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), | |
307 pending_tasks_); | |
308 } | |
309 | |
310 bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback( | |
311 const std::set<TestOrderablePendingTask>& existing_tasks) { | |
312 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); | |
313 } | |
314 | |
315 base::Callback<bool(void)> OrderedSimpleTaskRunner::NowBefore( | |
316 base::TimeTicks stop_at) { | |
317 return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback, | |
318 base::Unretained(this), | |
319 stop_at); | |
320 } | |
321 bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at) { | |
322 return NextTaskTime() <= stop_at; | |
323 } | |
324 | |
325 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { | |
326 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, | |
327 base::Unretained(this)); | |
328 } | |
329 | |
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); | |
334 } | |
335 return true; | |
336 } | |
337 | |
338 } // namespace cc | |
OLD | NEW |