Chromium Code Reviews| 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 |