Home | History | Annotate | Download | only in test
      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