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::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 // |
| 130 bool OrderedSimpleTaskRunner::RunPendingTasks() { |
| 131 return RunTasksUntil(RunOnlyExisting(this)); |
| 132 } |
| 133 |
| 134 bool OrderedSimpleTaskRunner::RunUntilIdle() { |
| 135 std::vector<base::Callback<bool(void)> > check_callbacks; |
| 136 return RunTasksUntil(check_callbacks); |
| 137 } |
| 138 |
| 139 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { |
| 140 return RunUntilTime(now_src_->Now() + period); |
| 141 } |
| 142 |
| 143 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { |
| 144 // If we are not auto advancing, force now forward to the time. |
| 145 if (!advance_now_ && now_src_->Now() < time) |
| 146 now_src_->SetNow(time); |
| 147 |
| 148 // Run tasks |
| 149 bool result = RunTasksUntil(RunOnlyBefore(this, now_src_, time)); |
| 150 |
| 151 // If we didn't end up at exactly the time given, force now forward to the |
| 152 // time. |
| 153 if (!result || pending_tasks_.begin()->GetTimeToRun() > time) |
| 154 now_src_->SetNow(time); |
| 155 |
| 156 return result; |
| 157 } |
| 158 |
| 159 bool OrderedSimpleTaskRunner::RunTasksUntil(const RunCheck& check_callback) { |
| 160 return RunTasksUntil(check_callback.AsCallback()); |
| 161 } |
| 162 |
| 163 bool OrderedSimpleTaskRunner::RunTasksUntil(RunCheck* check_callback) { |
| 164 return RunTasksUntil(check_callback->AsCallback()); |
| 165 } |
| 166 |
| 167 bool OrderedSimpleTaskRunner::RunTasksUntil( |
| 168 const std::vector<RunCheck*> check_callbacks) { |
| 169 std::vector<base::Callback<bool(void)> > check_callbacks_converted( |
| 170 check_callbacks.size()); |
| 171 for (size_t i = 0; i < check_callbacks.size(); i++) { |
| 172 check_callbacks_converted[i] = check_callbacks[i]->AsCallback(); |
| 173 } |
| 174 |
| 175 return RunTasksUntil(check_callbacks_converted); |
| 176 } |
| 177 |
| 178 bool OrderedSimpleTaskRunner::RunTasksUntil( |
| 179 base::Callback<bool(void)> check_callback) { |
| 180 std::vector<base::Callback<bool(void)> > check_callbacks = {check_callback}; |
| 181 return RunTasksUntil(check_callbacks); |
| 182 } |
| 183 |
| 184 bool OrderedSimpleTaskRunner::RunTasksUntil( |
| 185 const std::vector<base::Callback<bool(void)> > check_callbacks) { |
| 186 TRACE_EVENT1( |
| 187 "cc", "OrderedSimpleTaskRunner::RunPendingTasks", "this", AsValue()); |
| 188 DCHECK(thread_checker_.CalledOnValidThread()); |
| 189 |
| 190 // Make a copy so we can append some extra run checks. |
| 191 std::vector<base::Callback<bool(void)> > usable_check_callbacks( |
| 192 check_callbacks); |
| 193 |
| 194 // Provide a timeout so this doesn't loop forever. |
| 195 RunNTasks timeout(max_tasks_); |
| 196 usable_check_callbacks.push_back(timeout.AsCallback()); |
| 197 |
| 198 // If to advance now or not |
| 199 RunOnlyBefore only_before(this, now_src_, now_src_->Now()); |
| 200 RunAdvanceNow advance_now(this, now_src_); |
| 201 if (!advance_now_) { |
| 202 usable_check_callbacks.push_back(only_before.AsCallback()); |
| 203 } else { |
| 204 usable_check_callbacks.push_back(advance_now.AsCallback()); |
| 205 } |
| 206 |
| 207 if (inside_run_tasks_until_) |
| 208 return true; |
| 209 inside_run_tasks_until_ = true; |
| 210 |
| 211 while (pending_tasks_.size() > 0) { |
| 212 std::set<TestOrderablePendingTask>::iterator task_to_run = |
| 213 pending_tasks_.begin(); |
| 214 |
| 215 // Check if we should continue to run the tasks |
| 216 for (std::vector<base::Callback<bool(void)> >::iterator it = |
| 217 usable_check_callbacks.begin(); |
| 218 it != usable_check_callbacks.end(); |
| 219 it++) { |
| 220 if (!it->Run()) { |
| 221 goto run_tasks_until_exit; |
| 222 } |
| 223 } |
| 224 |
| 225 { |
| 226 TRACE_EVENT1("cc", |
| 227 "OrderedSimpleTaskRunner::RunPendingTasks running", |
| 228 "task", |
| 229 task_to_run->AsValue()); |
| 230 task_to_run->task.Run(); |
| 231 } |
| 232 |
| 233 pending_tasks_.erase(task_to_run); |
| 234 } |
| 235 |
| 236 run_tasks_until_exit: |
| 237 inside_run_tasks_until_ = false; |
| 238 |
| 239 return pending_tasks_.size() > 0; |
| 240 } |
| 241 |
| 242 base::TimeDelta OrderedSimpleTaskRunner::DelayToNextPendingTask() { |
| 243 DCHECK(thread_checker_.CalledOnValidThread()); |
| 244 |
| 245 if (pending_tasks_.size() <= 0) |
| 246 return base::TimeDelta::FromInternalValue( |
| 247 std::numeric_limits<int64_t>::max()); |
| 248 |
| 249 base::TimeDelta delay = |
| 250 pending_tasks_.begin()->GetTimeToRun() - now_src_->Now(); |
| 251 if (delay > base::TimeDelta()) |
| 252 return delay; |
| 253 return base::TimeDelta(); |
| 254 } |
| 255 |
| 256 // base::debug tracing functionality |
| 257 scoped_refptr<base::debug::ConvertableToTraceFormat> |
| 258 OrderedSimpleTaskRunner::AsValue() const { |
| 259 scoped_refptr<base::debug::TracedValue> state = |
| 260 new base::debug::TracedValue(); |
| 261 AsValueInto(state); |
| 262 return state; |
| 263 } |
| 264 |
| 265 void OrderedSimpleTaskRunner::AsValueInto( |
| 266 base::debug::TracedValue* state) const { |
| 267 state->SetInteger("pending_tasks", pending_tasks_.size()); |
| 268 for (std::set<TestOrderablePendingTask>::const_iterator it = |
| 269 pending_tasks_.begin(); |
| 270 it != pending_tasks_.end(); |
| 271 ++it) { |
| 272 state->BeginDictionary( |
| 273 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); |
| 274 it->AsValueInto(state); |
| 275 state->EndDictionary(); |
| 276 } |
| 277 now_src_->AsValueInto(state); |
| 278 } |
| 279 |
| 280 base::Callback<bool(void)> OrderedSimpleTaskRunner::RunCheck::AsCallback() |
| 281 const { |
| 282 return base::Bind( |
| 283 &RunCheck::Check, |
| 284 base::Unretained(const_cast<OrderedSimpleTaskRunner::RunCheck*>(this))); |
| 285 } |
| 286 |
| 287 OrderedSimpleTaskRunner::RunCheckNeedsNextTask::RunCheckNeedsNextTask( |
| 288 OrderedSimpleTaskRunner* task_runner) |
| 289 : task_runner_(task_runner) { |
| 290 } |
| 291 bool OrderedSimpleTaskRunner::RunCheckNeedsNextTask::Check() { |
| 292 DCHECK(task_runner_); |
| 293 DCHECK_GT(task_runner_->pending_tasks_.size(), 0U); |
| 294 return CheckWithTask(*task_runner_->pending_tasks_.begin()); |
| 295 } |
| 296 |
| 297 OrderedSimpleTaskRunner::RunNTasks::RunNTasks(size_t number) |
| 298 : tasks_run_(0), tasks_to_run_(number) { |
| 299 } |
| 300 OrderedSimpleTaskRunner::RunNTasks::~RunNTasks() { |
| 301 } |
| 302 bool OrderedSimpleTaskRunner::RunNTasks::Check() { |
| 303 return tasks_run_++ < tasks_to_run_; |
| 304 } |
| 305 |
| 306 OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime::RunCheckNeedsNextTaskTime( |
| 307 OrderedSimpleTaskRunner* task_runner, |
| 308 scoped_refptr<TestNowSource> now_src) |
| 309 : RunCheckNeedsNextTask(task_runner), now_src_(now_src) { |
| 310 } |
| 311 OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime:: |
| 312 ~RunCheckNeedsNextTaskTime() { |
| 313 } |
| 314 bool OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime::CheckWithTask( |
| 315 const TestOrderablePendingTask& next_task) { |
| 316 return CheckWithTaskTime(now_src_->Now(), next_task.GetTimeToRun()); |
| 317 } |
| 318 |
| 319 OrderedSimpleTaskRunner::RunOnlyBefore::RunOnlyBefore( |
| 320 OrderedSimpleTaskRunner* task_runner, |
| 321 scoped_refptr<TestNowSource> now_src, |
| 322 base::TimeTicks stop_at) |
| 323 : RunCheckNeedsNextTaskTime(task_runner, now_src), stop_at_(stop_at) { |
| 324 } |
| 325 OrderedSimpleTaskRunner::RunOnlyBefore::~RunOnlyBefore() { |
| 326 } |
| 327 bool OrderedSimpleTaskRunner::RunOnlyBefore::CheckWithTaskTime( |
| 328 base::TimeTicks now, |
| 329 base::TimeTicks next_task) { |
| 330 return next_task <= stop_at_; |
| 331 } |
| 332 |
| 333 OrderedSimpleTaskRunner::RunOnlyExisting::RunOnlyExisting( |
| 334 OrderedSimpleTaskRunner* task_runner) |
| 335 : RunCheckNeedsNextTask(task_runner), |
| 336 pending_tasks_(task_runner->pending_tasks_) { |
| 337 } |
| 338 OrderedSimpleTaskRunner::RunOnlyExisting::~RunOnlyExisting() { |
| 339 } |
| 340 bool OrderedSimpleTaskRunner::RunOnlyExisting::CheckWithTask( |
| 341 const TestOrderablePendingTask& next_task) { |
| 342 return pending_tasks_.find(next_task) != pending_tasks_.end(); |
| 343 } |
| 344 |
| 345 OrderedSimpleTaskRunner::RunAdvanceNow::RunAdvanceNow( |
| 346 OrderedSimpleTaskRunner* task_runner, |
| 347 scoped_refptr<TestNowSource> now_src) |
| 348 : RunCheckNeedsNextTaskTime(task_runner, now_src) { |
| 349 } |
| 350 OrderedSimpleTaskRunner::RunAdvanceNow::~RunAdvanceNow() { |
| 351 } |
| 352 bool OrderedSimpleTaskRunner::RunAdvanceNow::CheckWithTaskTime( |
| 353 base::TimeTicks now, |
| 354 base::TimeTicks next_task) { |
| 355 if (now < next_task) { |
| 356 now_src_->SetNow(next_task); |
| 357 } |
| 358 return true; |
39 } | 359 } |
40 | 360 |
41 } // namespace cc | 361 } // namespace cc |
OLD | NEW |