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/debug/trace_event.h" |
14 bool TestPendingTaskComparator(const base::TestPendingTask& lhs, | 14 #include "base/debug/trace_event_argument.h" |
15 const base::TestPendingTask& rhs) { | 15 #include "base/strings/string_number_conversions.h" |
16 return lhs.ShouldRunBefore(rhs); | 16 |
17 } | 17 #define TRACE_TASK(function, task) \ |
18 | 18 TRACE_EVENT_INSTANT1( \ |
19 } | 19 "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue()); |
20 | |
21 #define TRACE_TASK_RUN(function, tag, task) | |
20 | 22 |
21 namespace cc { | 23 namespace cc { |
22 | 24 |
23 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() {} | 25 // TestOrderablePendingTask implementation |
26 TestOrderablePendingTask::TestOrderablePendingTask() | |
27 : base::TestPendingTask(), | |
28 task_id_(TestOrderablePendingTask::task_id_counter++) { | |
29 } | |
30 | |
31 TestOrderablePendingTask::TestOrderablePendingTask( | |
32 const tracked_objects::Location& location, | |
33 const base::Closure& task, | |
34 base::TimeTicks post_time, | |
35 base::TimeDelta delay, | |
36 TestNestability nestability) | |
37 : base::TestPendingTask(location, task, post_time, delay, nestability), | |
38 task_id_(TestOrderablePendingTask::task_id_counter++) { | |
39 } | |
40 | |
41 size_t TestOrderablePendingTask::task_id_counter = 0; | |
42 | |
43 TestOrderablePendingTask::~TestOrderablePendingTask() { | |
44 } | |
45 | |
46 bool TestOrderablePendingTask::operator==( | |
47 const TestOrderablePendingTask& other) const { | |
48 return task_id_ == other.task_id_; | |
49 } | |
50 | |
51 bool TestOrderablePendingTask::operator<( | |
52 const TestOrderablePendingTask& other) const { | |
53 if (*this == other) | |
54 return false; | |
55 | |
56 if (GetTimeToRun() == other.GetTimeToRun()) { | |
57 return task_id_ < other.task_id_; | |
58 } | |
59 return ShouldRunBefore(other); | |
60 } | |
61 | |
62 scoped_refptr<base::debug::ConvertableToTraceFormat> | |
63 TestOrderablePendingTask::AsValue() const { | |
64 scoped_refptr<base::debug::TracedValue> state = | |
65 new base::debug::TracedValue(); | |
66 AsValueInto(state); | |
67 return state; | |
68 } | |
69 | |
70 void TestOrderablePendingTask::AsValueInto( | |
71 base::debug::TracedValue* state) const { | |
72 state->SetInteger("id", task_id_); | |
73 state->SetInteger("run_at", GetTimeToRun().ToInternalValue()); | |
74 state->SetString("posted_from", location.ToString()); | |
75 } | |
76 | |
77 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() | |
78 : advance_now_(true), | |
79 now_src_(TestNowSource::Create(0)), | |
80 inside_run_tasks_until_(false) { | |
81 } | |
82 | |
83 OrderedSimpleTaskRunner::OrderedSimpleTaskRunner( | |
84 scoped_refptr<TestNowSource> now_src, | |
85 bool advance_now) | |
86 : advance_now_(advance_now), | |
87 now_src_(now_src), | |
88 max_tasks_(absolute_max_tasks), | |
89 inside_run_tasks_until_(false) { | |
90 } | |
24 | 91 |
25 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} | 92 OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} |
26 | 93 |
27 void OrderedSimpleTaskRunner::RunPendingTasks() { | 94 // base::TestSimpleTaskRunner implementation |
28 DCHECK(thread_checker_.CalledOnValidThread()); | 95 bool OrderedSimpleTaskRunner::PostDelayedTask( |
29 // Swap with a local variable to avoid re-entrancy problems. | 96 const tracked_objects::Location& from_here, |
30 std::deque<base::TestPendingTask> tasks_to_run; | 97 const base::Closure& task, |
31 tasks_to_run.swap(pending_tasks_); | 98 base::TimeDelta delay) { |
32 std::stable_sort(tasks_to_run.begin(), | 99 DCHECK(thread_checker_.CalledOnValidThread()); |
33 tasks_to_run.end(), | 100 TestOrderablePendingTask pt( |
34 TestPendingTaskComparator); | 101 from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE); |
35 for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); | 102 |
36 it != tasks_to_run.end(); ++it) { | 103 TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt); |
37 it->task.Run(); | 104 pending_tasks_.insert(pt); |
38 } | 105 return true; |
106 } | |
107 | |
108 bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask( | |
109 const tracked_objects::Location& from_here, | |
110 const base::Closure& task, | |
111 base::TimeDelta delay) { | |
112 DCHECK(thread_checker_.CalledOnValidThread()); | |
113 TestOrderablePendingTask pt(from_here, | |
114 task, | |
115 now_src_->Now(), | |
116 delay, | |
117 base::TestPendingTask::NON_NESTABLE); | |
118 | |
119 TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt); | |
120 pending_tasks_.insert(pt); | |
121 return true; | |
122 } | |
123 | |
124 bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const { | |
125 DCHECK(thread_checker_.CalledOnValidThread()); | |
126 return true; | |
127 } | |
128 | |
129 base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() { | |
130 if (pending_tasks_.size() <= 0) | |
Sami
2014/09/01 11:35:33
nit: Add braces
mithro-old
2014/09/01 12:00:19
Done.
Sami
2014/09/01 12:50:29
No need for them now but oh well :)
| |
131 return base::TimeTicks::FromInternalValue( | |
132 std::numeric_limits<int64_t>::max()); | |
133 | |
134 return pending_tasks_.begin()->GetTimeToRun(); | |
135 } | |
136 | |
137 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() { | |
138 DCHECK(thread_checker_.CalledOnValidThread()); | |
139 | |
140 if (pending_tasks_.size() <= 0) | |
Sami
2014/09/01 11:35:33
nit: Add braces
mithro-old
2014/09/01 12:00:19
Done.
| |
141 return base::TimeDelta::FromInternalValue( | |
142 std::numeric_limits<int64_t>::max()); | |
143 | |
144 base::TimeDelta delay = NextTaskTime() - now_src_->Now(); | |
145 if (delay > base::TimeDelta()) | |
146 return delay; | |
147 return base::TimeDelta(); | |
148 } | |
149 | |
150 const size_t OrderedSimpleTaskRunner::absolute_max_tasks = | |
151 std::numeric_limits<size_t>::max(); | |
152 | |
153 bool OrderedSimpleTaskRunner::RunTasks(base::Callback<bool(void)> condition) { | |
154 std::vector<base::Callback<bool(void)> > conditions(1); | |
155 conditions[0] = condition; | |
156 return RunTasks(conditions); | |
157 } | |
158 | |
159 bool OrderedSimpleTaskRunner::RunTasks( | |
160 const std::vector<base::Callback<bool(void)> > conditions) { | |
161 TRACE_EVENT1( | |
162 "cc", "OrderedSimpleTaskRunner::RunPendingTasks", "this", AsValue()); | |
163 DCHECK(thread_checker_.CalledOnValidThread()); | |
164 | |
165 // Make a copy so we can append some extra run checks. | |
166 std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions); | |
167 | |
168 // Provide a timeout base on number of tasks run so this doesn't loop | |
169 // forever. | |
170 modifiable_conditions.push_back(WhileTaskRunCountBelow(max_tasks_)); | |
171 | |
172 // If to advance now or not | |
173 if (!advance_now_) { | |
174 modifiable_conditions.push_back(WhileNowBefore(now_src_->Now())); | |
175 } else { | |
176 modifiable_conditions.push_back(AdvanceNow()); | |
Sami
2014/09/01 11:35:33
It's clever but having AdvanceNow() as a condition
mithro-old
2014/09/01 12:00:19
Actually, come to think of it - there is actually
Sami
2014/09/01 12:50:29
I'm fine with conditions having side effects, but
| |
177 } | |
178 | |
179 if (inside_run_tasks_until_) | |
180 return true; | |
181 inside_run_tasks_until_ = true; | |
182 | |
183 while (pending_tasks_.size() > 0) { | |
184 // Check if we should continue to run pending tasks | |
185 for (std::vector<base::Callback<bool(void)> >::iterator it = | |
186 modifiable_conditions.begin(); | |
187 it != modifiable_conditions.end(); | |
188 it++) { | |
189 if (!it->Run()) { | |
190 goto run_tasks_exit; | |
Sami
2014/09/01 11:35:32
I feel like I almost have to offer an alternative
mithro-old
2014/09/01 12:00:19
Done.
Never seen base::AutoReset before! LGTM.
| |
191 } | |
192 } | |
193 | |
194 std::set<TestOrderablePendingTask>::iterator task_to_run = | |
195 pending_tasks_.begin(); | |
196 { | |
197 TRACE_EVENT1("cc", | |
198 "OrderedSimpleTaskRunner::RunPendingTasks running", | |
199 "task", | |
200 task_to_run->AsValue()); | |
201 task_to_run->task.Run(); | |
202 } | |
203 | |
204 pending_tasks_.erase(task_to_run); | |
205 } | |
206 | |
207 run_tasks_exit: | |
208 | |
209 inside_run_tasks_until_ = false; | |
210 return pending_tasks_.size() > 0; | |
211 } | |
212 | |
213 bool OrderedSimpleTaskRunner::RunPendingTasks() { | |
214 return RunTasks(WhileTaskExistedInitially()); | |
215 } | |
216 | |
217 bool OrderedSimpleTaskRunner::RunUntilIdle() { | |
218 return RunTasks(std::vector<base::Callback<bool(void)> >()); | |
219 } | |
220 | |
221 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { | |
222 // If we are not auto advancing, force now forward to the time. | |
223 if (!advance_now_ && now_src_->Now() < time) | |
224 now_src_->SetNow(time); | |
225 | |
226 // Run tasks | |
227 bool result = RunTasks(WhileNowBefore(time)); | |
228 | |
229 // If the next task is after the stopping time and auto-advancing now, then | |
230 // force time to be the stopping time. | |
231 if (!result && advance_now_ && now_src_->Now() < time) { | |
232 now_src_->SetNow(time); | |
233 } | |
234 | |
235 return result; | |
236 } | |
237 | |
238 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { | |
239 return RunUntilTime(now_src_->Now() + period); | |
240 } | |
241 | |
242 // base::debug tracing functionality | |
243 scoped_refptr<base::debug::ConvertableToTraceFormat> | |
244 OrderedSimpleTaskRunner::AsValue() const { | |
245 scoped_refptr<base::debug::TracedValue> state = | |
246 new base::debug::TracedValue(); | |
247 AsValueInto(state); | |
248 return state; | |
249 } | |
250 | |
251 void OrderedSimpleTaskRunner::AsValueInto( | |
252 base::debug::TracedValue* state) const { | |
253 state->SetInteger("pending_tasks", pending_tasks_.size()); | |
254 for (std::set<TestOrderablePendingTask>::const_iterator it = | |
255 pending_tasks_.begin(); | |
256 it != pending_tasks_.end(); | |
257 ++it) { | |
258 state->BeginDictionary( | |
259 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); | |
260 it->AsValueInto(state); | |
261 state->EndDictionary(); | |
262 } | |
263 now_src_->AsValueInto(state); | |
264 } | |
265 | |
266 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileTaskRunCountBelow( | |
267 size_t max_tasks) { | |
268 return base::Bind(&OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback, | |
269 base::Unretained(this), | |
270 max_tasks, | |
271 base::Owned(new size_t(0))); | |
272 } | |
273 bool OrderedSimpleTaskRunner::WhileTaskRunCountBelowCallback( | |
Sami
2014/09/01 11:35:33
nit: Add blank line.
mithro-old
2014/09/01 12:00:19
Done.
| |
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 bool OrderedSimpleTaskRunner::WhileTaskExistedInitiallyCallback( | |
Sami
2014/09/01 11:35:33
nit: Add blank line.
mithro-old
2014/09/01 12:00:19
Done.
| |
287 const std::set<TestOrderablePendingTask>& existing_tasks) { | |
288 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); | |
289 } | |
290 | |
291 base::Callback<bool(void)> OrderedSimpleTaskRunner::WhileNowBefore( | |
292 base::TimeTicks stop_at) { | |
293 return base::Bind(&OrderedSimpleTaskRunner::WhileNowBeforeCallback, | |
294 base::Unretained(this), | |
295 stop_at); | |
296 } | |
297 bool OrderedSimpleTaskRunner::WhileNowBeforeCallback(base::TimeTicks stop_at) { | |
Sami
2014/09/01 11:35:33
nit: add Blank line.
mithro-old
2014/09/01 12:00:19
Done.
| |
298 return NextTaskTime() <= stop_at; | |
299 } | |
300 | |
301 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { | |
302 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, | |
303 base::Unretained(this)); | |
304 } | |
305 | |
306 bool OrderedSimpleTaskRunner::AdvanceNowCallback() { | |
307 base::TimeTicks next_task_time = NextTaskTime(); | |
308 if (now_src_->Now() < next_task_time) { | |
309 now_src_->SetNow(next_task_time); | |
310 } | |
311 return true; | |
39 } | 312 } |
40 | 313 |
41 } // namespace cc | 314 } // namespace cc |
OLD | NEW |