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 |
index 188ffe72b5f8adea6208635d68263b3139811000..6ffe241e34628d1a11ff67b02529b08b38e94b7a 100644 |
--- a/cc/test/ordered_simple_task_runner.cc |
+++ b/cc/test/ordered_simple_task_runner.cc |
@@ -4,38 +4,358 @@ |
#include "cc/test/ordered_simple_task_runner.h" |
-#include <algorithm> |
-#include <deque> |
+#include <limits> |
+#include <set> |
+#include <sstream> |
+#include <string> |
+#include <vector> |
-#include "base/logging.h" |
+#include "base/debug/trace_event.h" |
+#include "base/debug/trace_event_argument.h" |
+#include "base/strings/string_number_conversions.h" |
-namespace { |
+#define TRACE_TASK(function, task) \ |
+ TRACE_EVENT_INSTANT1( \ |
+ "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue()); |
-bool TestPendingTaskComparator(const base::TestPendingTask& lhs, |
- const base::TestPendingTask& rhs) { |
- return lhs.ShouldRunBefore(rhs); |
+#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++) { |
} |
-namespace cc { |
+size_t TestOrderablePendingTask::TestOrderablePendingTask::task_id_counter = 0; |
-OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() {} |
+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::debug::ConvertableToTraceFormat> |
+TestOrderablePendingTask::AsValue() const { |
+ scoped_refptr<base::debug::TracedValue> state = |
+ new base::debug::TracedValue(); |
+ AsValueInto(state); |
+ return state; |
+} |
+ |
+void TestOrderablePendingTask::AsValueInto( |
+ base::debug::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_(absolute_max_tasks), |
+ inside_run_tasks_until_(false) { |
+} |
OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} |
-void OrderedSimpleTaskRunner::RunPendingTasks() { |
+// 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; |
+} |
+ |
+// |
+bool OrderedSimpleTaskRunner::RunPendingTasks() { |
+ return RunTasksUntil(RunOnlyExisting(this)); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunUntilIdle() { |
+ std::vector<base::Callback<bool(void)> > check_callbacks; |
+ return RunTasksUntil(check_callbacks); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { |
+ return RunUntilTime(now_src_->Now() + period); |
+} |
+ |
+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 = RunTasksUntil(RunOnlyBefore(this, now_src_, time)); |
+ |
+ // If we didn't end up at exactly the time given, force now forward to the |
+ // time. |
+ if (!result || pending_tasks_.begin()->GetTimeToRun() > time) |
+ now_src_->SetNow(time); |
+ |
+ return result; |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunTasksUntil(const RunCheck& check_callback) { |
+ return RunTasksUntil(check_callback.AsCallback()); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunTasksUntil(RunCheck* check_callback) { |
+ return RunTasksUntil(check_callback->AsCallback()); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunTasksUntil( |
+ const std::vector<RunCheck*> check_callbacks) { |
+ std::vector<base::Callback<bool(void)> > check_callbacks_converted( |
+ check_callbacks.size()); |
+ for (size_t i = 0; i < check_callbacks.size(); i++) { |
+ check_callbacks_converted[i] = check_callbacks[i]->AsCallback(); |
+ } |
+ |
+ return RunTasksUntil(check_callbacks_converted); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunTasksUntil( |
+ base::Callback<bool(void)> check_callback) { |
+ std::vector<base::Callback<bool(void)> > check_callbacks = {check_callback}; |
+ return RunTasksUntil(check_callbacks); |
+} |
+ |
+bool OrderedSimpleTaskRunner::RunTasksUntil( |
+ const std::vector<base::Callback<bool(void)> > check_callbacks) { |
+ TRACE_EVENT1( |
+ "cc", "OrderedSimpleTaskRunner::RunPendingTasks", "this", AsValue()); |
DCHECK(thread_checker_.CalledOnValidThread()); |
- // Swap with a local variable to avoid re-entrancy problems. |
- std::deque<base::TestPendingTask> tasks_to_run; |
- tasks_to_run.swap(pending_tasks_); |
- std::stable_sort(tasks_to_run.begin(), |
- tasks_to_run.end(), |
- TestPendingTaskComparator); |
- for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); |
- it != tasks_to_run.end(); ++it) { |
- it->task.Run(); |
+ |
+ // Make a copy so we can append some extra run checks. |
+ std::vector<base::Callback<bool(void)> > usable_check_callbacks( |
+ check_callbacks); |
+ |
+ // Provide a timeout so this doesn't loop forever. |
+ RunNTasks timeout(max_tasks_); |
+ usable_check_callbacks.push_back(timeout.AsCallback()); |
+ |
+ // If to advance now or not |
+ RunOnlyBefore only_before(this, now_src_, now_src_->Now()); |
+ RunAdvanceNow advance_now(this, now_src_); |
+ if (!advance_now_) { |
+ usable_check_callbacks.push_back(only_before.AsCallback()); |
+ } else { |
+ usable_check_callbacks.push_back(advance_now.AsCallback()); |
+ } |
+ |
+ if (inside_run_tasks_until_) |
+ return true; |
+ inside_run_tasks_until_ = true; |
+ |
+ while (pending_tasks_.size() > 0) { |
+ std::set<TestOrderablePendingTask>::iterator task_to_run = |
+ pending_tasks_.begin(); |
+ |
+ // Check if we should continue to run the tasks |
+ for (std::vector<base::Callback<bool(void)> >::iterator it = |
+ usable_check_callbacks.begin(); |
+ it != usable_check_callbacks.end(); |
+ it++) { |
+ if (!it->Run()) { |
+ goto run_tasks_until_exit; |
+ } |
+ } |
+ |
+ { |
+ TRACE_EVENT1("cc", |
+ "OrderedSimpleTaskRunner::RunPendingTasks running", |
+ "task", |
+ task_to_run->AsValue()); |
+ task_to_run->task.Run(); |
+ } |
+ |
+ pending_tasks_.erase(task_to_run); |
+ } |
+ |
+run_tasks_until_exit: |
+ inside_run_tasks_until_ = false; |
+ |
+ return pending_tasks_.size() > 0; |
+} |
+ |
+base::TimeDelta OrderedSimpleTaskRunner::DelayToNextPendingTask() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (pending_tasks_.size() <= 0) |
+ return base::TimeDelta::FromInternalValue( |
+ std::numeric_limits<int64_t>::max()); |
+ |
+ base::TimeDelta delay = |
+ pending_tasks_.begin()->GetTimeToRun() - now_src_->Now(); |
+ if (delay > base::TimeDelta()) |
+ return delay; |
+ return base::TimeDelta(); |
+} |
+ |
+// base::debug tracing functionality |
+scoped_refptr<base::debug::ConvertableToTraceFormat> |
+OrderedSimpleTaskRunner::AsValue() const { |
+ scoped_refptr<base::debug::TracedValue> state = |
+ new base::debug::TracedValue(); |
+ AsValueInto(state); |
+ return state; |
+} |
+ |
+void OrderedSimpleTaskRunner::AsValueInto( |
+ base::debug::TracedValue* state) const { |
+ state->SetInteger("pending_tasks", pending_tasks_.size()); |
+ for (std::set<TestOrderablePendingTask>::const_iterator it = |
+ pending_tasks_.begin(); |
+ it != pending_tasks_.end(); |
+ ++it) { |
+ state->BeginDictionary( |
+ base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); |
+ it->AsValueInto(state); |
+ state->EndDictionary(); |
+ } |
+ now_src_->AsValueInto(state); |
+} |
+ |
+base::Callback<bool(void)> OrderedSimpleTaskRunner::RunCheck::AsCallback() |
+ const { |
+ return base::Bind( |
+ &RunCheck::Check, |
+ base::Unretained(const_cast<OrderedSimpleTaskRunner::RunCheck*>(this))); |
+} |
+ |
+OrderedSimpleTaskRunner::RunCheckNeedsNextTask::RunCheckNeedsNextTask( |
+ OrderedSimpleTaskRunner* task_runner) |
+ : task_runner_(task_runner) { |
+} |
+bool OrderedSimpleTaskRunner::RunCheckNeedsNextTask::Check() { |
+ DCHECK(task_runner_); |
+ DCHECK_GT(task_runner_->pending_tasks_.size(), 0U); |
+ return CheckWithTask(*task_runner_->pending_tasks_.begin()); |
+} |
+ |
+OrderedSimpleTaskRunner::RunNTasks::RunNTasks(size_t number) |
+ : tasks_run_(0), tasks_to_run_(number) { |
+} |
+OrderedSimpleTaskRunner::RunNTasks::~RunNTasks() { |
+} |
+bool OrderedSimpleTaskRunner::RunNTasks::Check() { |
+ return tasks_run_++ < tasks_to_run_; |
+} |
+ |
+OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime::RunCheckNeedsNextTaskTime( |
+ OrderedSimpleTaskRunner* task_runner, |
+ scoped_refptr<TestNowSource> now_src) |
+ : RunCheckNeedsNextTask(task_runner), now_src_(now_src) { |
+} |
+OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime:: |
+ ~RunCheckNeedsNextTaskTime() { |
+} |
+bool OrderedSimpleTaskRunner::RunCheckNeedsNextTaskTime::CheckWithTask( |
+ const TestOrderablePendingTask& next_task) { |
+ return CheckWithTaskTime(now_src_->Now(), next_task.GetTimeToRun()); |
+} |
+ |
+OrderedSimpleTaskRunner::RunOnlyBefore::RunOnlyBefore( |
+ OrderedSimpleTaskRunner* task_runner, |
+ scoped_refptr<TestNowSource> now_src, |
+ base::TimeTicks stop_at) |
+ : RunCheckNeedsNextTaskTime(task_runner, now_src), stop_at_(stop_at) { |
+} |
+OrderedSimpleTaskRunner::RunOnlyBefore::~RunOnlyBefore() { |
+} |
+bool OrderedSimpleTaskRunner::RunOnlyBefore::CheckWithTaskTime( |
+ base::TimeTicks now, |
+ base::TimeTicks next_task) { |
+ return next_task <= stop_at_; |
+} |
+ |
+OrderedSimpleTaskRunner::RunOnlyExisting::RunOnlyExisting( |
+ OrderedSimpleTaskRunner* task_runner) |
+ : RunCheckNeedsNextTask(task_runner), |
+ pending_tasks_(task_runner->pending_tasks_) { |
+} |
+OrderedSimpleTaskRunner::RunOnlyExisting::~RunOnlyExisting() { |
+} |
+bool OrderedSimpleTaskRunner::RunOnlyExisting::CheckWithTask( |
+ const TestOrderablePendingTask& next_task) { |
+ return pending_tasks_.find(next_task) != pending_tasks_.end(); |
+} |
+ |
+OrderedSimpleTaskRunner::RunAdvanceNow::RunAdvanceNow( |
+ OrderedSimpleTaskRunner* task_runner, |
+ scoped_refptr<TestNowSource> now_src) |
+ : RunCheckNeedsNextTaskTime(task_runner, now_src) { |
+} |
+OrderedSimpleTaskRunner::RunAdvanceNow::~RunAdvanceNow() { |
+} |
+bool OrderedSimpleTaskRunner::RunAdvanceNow::CheckWithTaskTime( |
+ base::TimeTicks now, |
+ base::TimeTicks next_task) { |
+ if (now < next_task) { |
+ now_src_->SetNow(next_task); |
} |
+ return true; |
} |
} // namespace cc |