123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- // Copyright (c) 2012 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 "base/test/sequenced_task_runner_test_template.h"
- #include <ostream>
- #include "base/location.h"
- namespace base {
- namespace internal {
- TaskEvent::TaskEvent(int i, Type type)
- : i(i), type(type) {
- }
- SequencedTaskTracker::SequencedTaskTracker()
- : next_post_i_(0),
- task_end_count_(0),
- task_end_cv_(&lock_) {
- }
- void SequencedTaskTracker::PostWrappedNonNestableTask(
- SequencedTaskRunner* task_runner,
- OnceClosure task) {
- AutoLock event_lock(lock_);
- const int post_i = next_post_i_++;
- auto wrapped_task =
- BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
- task_runner->PostNonNestableTask(FROM_HERE, std::move(wrapped_task));
- TaskPosted(post_i);
- }
- void SequencedTaskTracker::PostWrappedNestableTask(
- SequencedTaskRunner* task_runner,
- OnceClosure task) {
- AutoLock event_lock(lock_);
- const int post_i = next_post_i_++;
- auto wrapped_task =
- BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
- task_runner->PostTask(FROM_HERE, std::move(wrapped_task));
- TaskPosted(post_i);
- }
- void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
- SequencedTaskRunner* task_runner,
- OnceClosure task,
- TimeDelta delay) {
- AutoLock event_lock(lock_);
- const int post_i = next_post_i_++;
- auto wrapped_task =
- BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
- task_runner->PostNonNestableDelayedTask(FROM_HERE, std::move(wrapped_task),
- delay);
- TaskPosted(post_i);
- }
- void SequencedTaskTracker::PostNonNestableTasks(
- SequencedTaskRunner* task_runner,
- int task_count) {
- for (int i = 0; i < task_count; ++i) {
- PostWrappedNonNestableTask(task_runner, OnceClosure());
- }
- }
- void SequencedTaskTracker::RunTask(OnceClosure task, int task_i) {
- TaskStarted(task_i);
- if (!task.is_null())
- std::move(task).Run();
- TaskEnded(task_i);
- }
- void SequencedTaskTracker::TaskPosted(int i) {
- // Caller must own |lock_|.
- events_.push_back(TaskEvent(i, TaskEvent::POST));
- }
- void SequencedTaskTracker::TaskStarted(int i) {
- AutoLock lock(lock_);
- events_.push_back(TaskEvent(i, TaskEvent::START));
- }
- void SequencedTaskTracker::TaskEnded(int i) {
- AutoLock lock(lock_);
- events_.push_back(TaskEvent(i, TaskEvent::END));
- ++task_end_count_;
- task_end_cv_.Signal();
- }
- const std::vector<TaskEvent>&
- SequencedTaskTracker::GetTaskEvents() const {
- return events_;
- }
- void SequencedTaskTracker::WaitForCompletedTasks(int count) {
- AutoLock lock(lock_);
- while (task_end_count_ < count)
- task_end_cv_.Wait();
- }
- SequencedTaskTracker::~SequencedTaskTracker() = default;
- void PrintTo(const TaskEvent& event, std::ostream* os) {
- *os << "(i=" << event.i << ", type=";
- switch (event.type) {
- case TaskEvent::POST: *os << "POST"; break;
- case TaskEvent::START: *os << "START"; break;
- case TaskEvent::END: *os << "END"; break;
- }
- *os << ")";
- }
- namespace {
- // Returns the task ordinals for the task event type |type| in the order that
- // they were recorded.
- std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events,
- TaskEvent::Type type) {
- std::vector<int> tasks;
- std::vector<TaskEvent>::const_iterator event;
- for (event = events.begin(); event != events.end(); ++event) {
- if (event->type == type)
- tasks.push_back(event->i);
- }
- return tasks;
- }
- // Returns all task events for task |task_i|.
- std::vector<TaskEvent::Type> GetEventsForTask(
- const std::vector<TaskEvent>& events,
- int task_i) {
- std::vector<TaskEvent::Type> task_event_orders;
- std::vector<TaskEvent>::const_iterator event;
- for (event = events.begin(); event != events.end(); ++event) {
- if (event->i == task_i)
- task_event_orders.push_back(event->type);
- }
- return task_event_orders;
- }
- // Checks that the task events for each task in |events| occur in the order
- // {POST, START, END}, and that there is only one instance of each event type
- // per task.
- ::testing::AssertionResult CheckEventOrdersForEachTask(
- const std::vector<TaskEvent>& events,
- int task_count) {
- std::vector<TaskEvent::Type> expected_order;
- expected_order.push_back(TaskEvent::POST);
- expected_order.push_back(TaskEvent::START);
- expected_order.push_back(TaskEvent::END);
- // This is O(n^2), but it runs fast enough currently so is not worth
- // optimizing.
- for (int i = 0; i < task_count; ++i) {
- const std::vector<TaskEvent::Type> task_events =
- GetEventsForTask(events, i);
- if (task_events != expected_order) {
- return ::testing::AssertionFailure()
- << "Events for task " << i << " are out of order; expected: "
- << ::testing::PrintToString(expected_order) << "; actual: "
- << ::testing::PrintToString(task_events);
- }
- }
- return ::testing::AssertionSuccess();
- }
- // Checks that no two tasks were running at the same time. I.e. the only
- // events allowed between the START and END of a task are the POSTs of other
- // tasks.
- ::testing::AssertionResult CheckNoTaskRunsOverlap(
- const std::vector<TaskEvent>& events) {
- // If > -1, we're currently inside a START, END pair.
- int current_task_i = -1;
- std::vector<TaskEvent>::const_iterator event;
- for (event = events.begin(); event != events.end(); ++event) {
- bool spurious_event_found = false;
- if (current_task_i == -1) { // Not inside a START, END pair.
- switch (event->type) {
- case TaskEvent::POST:
- break;
- case TaskEvent::START:
- current_task_i = event->i;
- break;
- case TaskEvent::END:
- spurious_event_found = true;
- break;
- }
- } else { // Inside a START, END pair.
- bool interleaved_task_detected = false;
- switch (event->type) {
- case TaskEvent::POST:
- if (event->i == current_task_i)
- spurious_event_found = true;
- break;
- case TaskEvent::START:
- interleaved_task_detected = true;
- break;
- case TaskEvent::END:
- if (event->i != current_task_i)
- interleaved_task_detected = true;
- else
- current_task_i = -1;
- break;
- }
- if (interleaved_task_detected) {
- return ::testing::AssertionFailure()
- << "Found event " << ::testing::PrintToString(*event)
- << " between START and END events for task " << current_task_i
- << "; event dump: " << ::testing::PrintToString(events);
- }
- }
- if (spurious_event_found) {
- const int event_i = event - events.begin();
- return ::testing::AssertionFailure()
- << "Spurious event " << ::testing::PrintToString(*event)
- << " at position " << event_i << "; event dump: "
- << ::testing::PrintToString(events);
- }
- }
- return ::testing::AssertionSuccess();
- }
- } // namespace
- ::testing::AssertionResult CheckNonNestableInvariants(
- const std::vector<TaskEvent>& events,
- int task_count) {
- const std::vector<int> post_order =
- GetEventTypeOrder(events, TaskEvent::POST);
- const std::vector<int> start_order =
- GetEventTypeOrder(events, TaskEvent::START);
- const std::vector<int> end_order =
- GetEventTypeOrder(events, TaskEvent::END);
- if (start_order != post_order) {
- return ::testing::AssertionFailure()
- << "Expected START order (which equals actual POST order): \n"
- << ::testing::PrintToString(post_order)
- << "\n Actual START order:\n"
- << ::testing::PrintToString(start_order);
- }
- if (end_order != post_order) {
- return ::testing::AssertionFailure()
- << "Expected END order (which equals actual POST order): \n"
- << ::testing::PrintToString(post_order)
- << "\n Actual END order:\n"
- << ::testing::PrintToString(end_order);
- }
- const ::testing::AssertionResult result =
- CheckEventOrdersForEachTask(events, task_count);
- if (!result)
- return result;
- return CheckNoTaskRunsOverlap(events);
- }
- } // namespace internal
- // This suite is instantiated in binaries that use //base:test_support.
- GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SequencedTaskRunnerTest);
- } // namespace base
|