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/debug/trace_event.h" 15 #include "base/debug/trace_event_argument.h" 16 #include "base/strings/string_number_conversions.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::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 } 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 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 bool condition_success = true; 194 for (std::vector<base::Callback<bool(void)> >::iterator it = 195 modifiable_conditions.begin(); 196 it != modifiable_conditions.end(); 197 it++) { 198 condition_success = it->Run(); 199 if (!condition_success) 200 break; 201 } 202 203 // Conditions could modify the pending task length, so we need to recheck 204 // that there are tasks to run. 205 if (!condition_success || pending_tasks_.size() == 0) { 206 break; 207 } 208 209 std::set<TestOrderablePendingTask>::iterator task_to_run = 210 pending_tasks_.begin(); 211 { 212 TRACE_EVENT1("cc", 213 "OrderedSimpleTaskRunner::RunPendingTasks running", 214 "task", 215 task_to_run->AsValue()); 216 task_to_run->task.Run(); 217 } 218 219 pending_tasks_.erase(task_to_run); 220 } 221 222 return pending_tasks_.size() > 0; 223 } 224 225 bool OrderedSimpleTaskRunner::RunPendingTasks() { 226 return RunTasksWhile(TaskExistedInitially()); 227 } 228 229 bool OrderedSimpleTaskRunner::RunUntilIdle() { 230 return RunTasksWhile(std::vector<base::Callback<bool(void)> >()); 231 } 232 233 bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { 234 // If we are not auto advancing, force now forward to the time. 235 if (!advance_now_ && now_src_->Now() < time) 236 now_src_->SetNow(time); 237 238 // Run tasks 239 bool result = RunTasksWhile(NowBefore(time)); 240 241 // If the next task is after the stopping time and auto-advancing now, then 242 // force time to be the stopping time. 243 if (!result && advance_now_ && now_src_->Now() < time) { 244 now_src_->SetNow(time); 245 } 246 247 return result; 248 } 249 250 bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { 251 return RunUntilTime(now_src_->Now() + period); 252 } 253 254 // base::debug tracing functionality 255 scoped_refptr<base::debug::ConvertableToTraceFormat> 256 OrderedSimpleTaskRunner::AsValue() const { 257 scoped_refptr<base::debug::TracedValue> state = 258 new base::debug::TracedValue(); 259 AsValueInto(state.get()); 260 return state; 261 } 262 263 void OrderedSimpleTaskRunner::AsValueInto( 264 base::debug::TracedValue* state) const { 265 state->SetInteger("pending_tasks", pending_tasks_.size()); 266 for (std::set<TestOrderablePendingTask>::const_iterator it = 267 pending_tasks_.begin(); 268 it != pending_tasks_.end(); 269 ++it) { 270 state->BeginDictionary( 271 base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); 272 it->AsValueInto(state); 273 state->EndDictionary(); 274 } 275 now_src_->AsValueInto(state); 276 } 277 278 base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow( 279 size_t max_tasks) { 280 return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback, 281 max_tasks, 282 base::Owned(new size_t(0))); 283 } 284 285 bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks, 286 size_t* tasks_run) { 287 return (*tasks_run)++ < max_tasks; 288 } 289 290 base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() { 291 // base::Bind takes a copy of pending_tasks_ 292 return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback, 293 base::Unretained(this), 294 pending_tasks_); 295 } 296 297 bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback( 298 const std::set<TestOrderablePendingTask>& existing_tasks) { 299 return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); 300 } 301 302 base::Callback<bool(void)> OrderedSimpleTaskRunner::NowBefore( 303 base::TimeTicks stop_at) { 304 return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback, 305 base::Unretained(this), 306 stop_at); 307 } 308 bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at) { 309 return NextTaskTime() <= stop_at; 310 } 311 312 base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { 313 return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, 314 base::Unretained(this)); 315 } 316 317 bool OrderedSimpleTaskRunner::AdvanceNowCallback() { 318 base::TimeTicks next_task_time = NextTaskTime(); 319 if (now_src_->Now() < next_task_time) { 320 now_src_->SetNow(next_task_time); 321 } 322 return true; 323 } 324 325 } // namespace cc 326