Index: cc/test/ordered_simple_task_runner.cc |
diff --git a/cc/test/ordered_simple_task_runner.cc b/cc/test/ordered_simple_task_runner.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9fc22aded6d73a1d0bee912fe0fcf275bb3910b4 |
--- /dev/null |
+++ b/cc/test/ordered_simple_task_runner.cc |
@@ -0,0 +1,338 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "cc/test/ordered_simple_task_runner.h" |
+ |
+#include <limits> |
+#include <set> |
+#include <sstream> |
+#include <string> |
+#include <vector> |
+ |
+#include "base/auto_reset.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/trace_event/trace_event.h" |
+#include "base/trace_event/trace_event_argument.h" |
+ |
+#define TRACE_TASK(function, task) \ |
+ TRACE_EVENT_INSTANT1( \ |
+ "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue()); |
+ |
+#define TRACE_TASK_RUN(function, tag, task) |
+ |
+namespace cc { |
+ |
+// TestOrderablePendingTask implementation |
+TestOrderablePendingTask::TestOrderablePendingTask() |
+ : base::TestPendingTask(), |
+ task_id_(TestOrderablePendingTask::task_id_counter++) { |
+} |
+ |
+TestOrderablePendingTask::TestOrderablePendingTask( |
+ const tracked_objects::Location& location, |
+ const base::Closure& task, |
+ base::TimeTicks post_time, |
+ base::TimeDelta delay, |
+ TestNestability nestability) |
+ : base::TestPendingTask(location, task, post_time, delay, nestability), |
+ task_id_(TestOrderablePendingTask::task_id_counter++) { |
+} |
+ |
+size_t TestOrderablePendingTask::task_id_counter = 0; |
+ |
+TestOrderablePendingTask::~TestOrderablePendingTask() { |
+} |
+ |
+bool TestOrderablePendingTask::operator==( |
+ const TestOrderablePendingTask& other) const { |
+ return task_id_ == other.task_id_; |
+} |
+ |
+bool TestOrderablePendingTask::operator<( |
+ const TestOrderablePendingTask& other) const { |
+ if (*this == other) |
+ return false; |
+ |
+ if (GetTimeToRun() == other.GetTimeToRun()) { |
+ return task_id_ < other.task_id_; |
+ } |
+ return ShouldRunBefore(other); |
+} |
+ |
+scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
+TestOrderablePendingTask::AsValue() const { |
+ scoped_refptr<base::trace_event::TracedValue> state = |
+ new base::trace_event::TracedValue(); |
+ AsValueInto(state.get()); |
+ return state; |
+} |
+ |
+void TestOrderablePendingTask::AsValueInto( |
+ base::trace_event::TracedValue* state) const { |
+ state->SetInteger("id", task_id_); |
+ state->SetInteger("run_at", GetTimeToRun().ToInternalValue()); |
+ state->SetString("posted_from", location.ToString()); |
+} |
+ |
+OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() |
+ : advance_now_(true), |
+ now_src_(TestNowSource::Create(0)), |
+ inside_run_tasks_until_(false) { |
+} |
+ |
+OrderedSimpleTaskRunner::OrderedSimpleTaskRunner( |
+ scoped_refptr<TestNowSource> now_src, |
+ bool advance_now) |
+ : advance_now_(advance_now), |
+ now_src_(now_src), |
+ max_tasks_(kAbsoluteMaxTasks), |
+ inside_run_tasks_until_(false) { |
+} |
+ |
+OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} |
+ |
+// base::TestSimpleTaskRunner implementation |
+bool OrderedSimpleTaskRunner::PostDelayedTask( |
+ const tracked_objects::Location& from_here, |
+ const base::Closure& task, |
+ base::TimeDelta delay) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ TestOrderablePendingTask pt( |
+ from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE); |
+ |
+ TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt); |
+ pending_tasks_.insert(pt); |
+ return true; |
+} |
+ |
+bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask( |
+ const tracked_objects::Location& from_here, |
+ const base::Closure& task, |
+ base::TimeDelta delay) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ TestOrderablePendingTask pt(from_here, |
+ task, |
+ now_src_->Now(), |
+ delay, |
+ base::TestPendingTask::NON_NESTABLE); |
+ |
+ TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt); |
+ pending_tasks_.insert(pt); |
+ return true; |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ return true; |
+} |
+ |
+size_t OrderedSimpleTaskRunner::NumPendingTasks() const { |
+ return pending_tasks_.size(); |
+} |
+ |
+bool OrderedSimpleTaskRunner::HasPendingTasks() const { |
+ return pending_tasks_.size() > 0; |
+} |
+ |
+base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() { |
+ if (pending_tasks_.size() <= 0) { |
+ return TestNowSource::kAbsoluteMaxNow; |
+ } |
+ |
+ return pending_tasks_.begin()->GetTimeToRun(); |
+} |
+ |
+base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (pending_tasks_.size() <= 0) { |
+ return TestNowSource::kAbsoluteMaxNow - base::TimeTicks(); |
+ } |
+ |
+ base::TimeDelta delay = NextTaskTime() - now_src_->Now(); |
+ if (delay > base::TimeDelta()) |
+ return delay; |
+ return base::TimeDelta(); |
+} |
+ |
+const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks = |
+ std::numeric_limits<size_t>::max(); |
+ |
+bool OrderedSimpleTaskRunner::RunTasksWhile( |
+ base::Callback<bool(void)> condition) { |
+ std::vector<base::Callback<bool(void)>> conditions(1); |
+ conditions[0] = condition; |
+ return RunTasksWhile(conditions); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunTasksWhile( |
+ const std::vector<base::Callback<bool(void)>>& conditions) { |
+ TRACE_EVENT2("cc", |
+ "OrderedSimpleTaskRunner::RunPendingTasks", |
+ "this", |
+ AsValue(), |
+ "nested", |
+ inside_run_tasks_until_); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (inside_run_tasks_until_) |
+ return true; |
+ |
+ base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_, |
+ true); |
+ |
+ // Make a copy so we can append some extra run checks. |
+ std::vector<base::Callback<bool(void)>> modifiable_conditions(conditions); |
+ |
+ // Provide a timeout base on number of tasks run so this doesn't loop |
+ // forever. |
+ modifiable_conditions.push_back(TaskRunCountBelow(max_tasks_)); |
+ |
+ // If to advance now or not |
+ if (!advance_now_) { |
+ modifiable_conditions.push_back(NowBefore(now_src_->Now())); |
+ } else { |
+ modifiable_conditions.push_back(AdvanceNow()); |
+ } |
+ |
+ while (pending_tasks_.size() > 0) { |
+ // Check if we should continue to run pending tasks. |
+ bool condition_success = true; |
+ for (std::vector<base::Callback<bool(void)>>::iterator it = |
+ modifiable_conditions.begin(); |
+ it != modifiable_conditions.end(); |
+ it++) { |
+ condition_success = it->Run(); |
+ if (!condition_success) |
+ break; |
+ } |
+ |
+ // Conditions could modify the pending task length, so we need to recheck |
+ // that there are tasks to run. |
+ if (!condition_success || !HasPendingTasks()) { |
+ break; |
+ } |
+ |
+ std::set<TestOrderablePendingTask>::iterator task_to_run = |
+ pending_tasks_.begin(); |
+ { |
+ TRACE_EVENT1("cc", |
+ "OrderedSimpleTaskRunner::RunPendingTasks running", |
+ "task", |
+ task_to_run->AsValue()); |
+ task_to_run->task.Run(); |
+ } |
+ |
+ pending_tasks_.erase(task_to_run); |
+ } |
+ |
+ return HasPendingTasks(); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunPendingTasks() { |
+ return RunTasksWhile(TaskExistedInitially()); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunUntilIdle() { |
+ return RunTasksWhile(std::vector<base::Callback<bool(void)>>()); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { |
+ // If we are not auto advancing, force now forward to the time. |
+ if (!advance_now_ && now_src_->Now() < time) |
+ now_src_->SetNow(time); |
+ |
+ // Run tasks |
+ bool result = RunTasksWhile(NowBefore(time)); |
+ |
+ // If the next task is after the stopping time and auto-advancing now, then |
+ // force time to be the stopping time. |
+ if (!result && advance_now_ && now_src_->Now() < time) { |
+ now_src_->SetNow(time); |
+ } |
+ |
+ return result; |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { |
+ return RunUntilTime(now_src_->Now() + period); |
+} |
+ |
+// base::trace_event tracing functionality |
+scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
+OrderedSimpleTaskRunner::AsValue() const { |
+ scoped_refptr<base::trace_event::TracedValue> state = |
+ new base::trace_event::TracedValue(); |
+ AsValueInto(state.get()); |
+ return state; |
+} |
+ |
+void OrderedSimpleTaskRunner::AsValueInto( |
+ base::trace_event::TracedValue* state) const { |
+ state->SetInteger("pending_tasks", pending_tasks_.size()); |
+ |
+ state->BeginArray("tasks"); |
+ for (std::set<TestOrderablePendingTask>::const_iterator it = |
+ pending_tasks_.begin(); |
+ it != pending_tasks_.end(); |
+ ++it) { |
+ state->BeginDictionary(); |
+ it->AsValueInto(state); |
+ state->EndDictionary(); |
+ } |
+ state->EndArray(); |
+ |
+ state->BeginDictionary("now_src"); |
+ now_src_->AsValueInto(state); |
+ state->EndDictionary(); |
+} |
+ |
+base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow( |
+ size_t max_tasks) { |
+ return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback, |
+ max_tasks, |
+ base::Owned(new size_t(0))); |
+} |
+ |
+bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks, |
+ size_t* tasks_run) { |
+ return (*tasks_run)++ < max_tasks; |
+} |
+ |
+base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() { |
+ // base::Bind takes a copy of pending_tasks_ |
+ return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback, |
+ base::Unretained(this), |
+ pending_tasks_); |
+} |
+ |
+bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback( |
+ const std::set<TestOrderablePendingTask>& existing_tasks) { |
+ return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); |
+} |
+ |
+base::Callback<bool(void)> OrderedSimpleTaskRunner::NowBefore( |
+ base::TimeTicks stop_at) { |
+ return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback, |
+ base::Unretained(this), |
+ stop_at); |
+} |
+bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at) { |
+ return NextTaskTime() <= stop_at; |
+} |
+ |
+base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { |
+ return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, |
+ base::Unretained(this)); |
+} |
+ |
+bool OrderedSimpleTaskRunner::AdvanceNowCallback() { |
+ base::TimeTicks next_task_time = NextTaskTime(); |
+ if (now_src_->Now() < next_task_time) { |
+ now_src_->SetNow(next_task_time); |
+ } |
+ return true; |
+} |
+ |
+} // namespace cc |