1 // Copyright (c) 2012 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 "base/test/sequenced_task_runner_test_template.h" 6 7 #include <ostream> 8 9 #include "base/location.h" 10 11 namespace base { 12 13 namespace internal { 14 15 TaskEvent::TaskEvent(int i, Type type) 16 : i(i), type(type) { 17 } 18 19 SequencedTaskTracker::SequencedTaskTracker() 20 : next_post_i_(0), 21 task_end_count_(0), 22 task_end_cv_(&lock_) { 23 } 24 25 void SequencedTaskTracker::PostWrappedNonNestableTask( 26 const scoped_refptr<SequencedTaskRunner>& task_runner, 27 const Closure& task) { 28 AutoLock event_lock(lock_); 29 const int post_i = next_post_i_++; 30 Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this, 31 task, post_i); 32 task_runner->PostNonNestableTask(FROM_HERE, wrapped_task); 33 TaskPosted(post_i); 34 } 35 36 void SequencedTaskTracker::PostWrappedNestableTask( 37 const scoped_refptr<SequencedTaskRunner>& task_runner, 38 const Closure& task) { 39 AutoLock event_lock(lock_); 40 const int post_i = next_post_i_++; 41 Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this, 42 task, post_i); 43 task_runner->PostTask(FROM_HERE, wrapped_task); 44 TaskPosted(post_i); 45 } 46 47 void SequencedTaskTracker::PostWrappedDelayedNonNestableTask( 48 const scoped_refptr<SequencedTaskRunner>& task_runner, 49 const Closure& task, 50 TimeDelta delay) { 51 AutoLock event_lock(lock_); 52 const int post_i = next_post_i_++; 53 Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this, 54 task, post_i); 55 task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay); 56 TaskPosted(post_i); 57 } 58 59 void SequencedTaskTracker::PostNonNestableTasks( 60 const scoped_refptr<SequencedTaskRunner>& task_runner, 61 int task_count) { 62 for (int i = 0; i < task_count; ++i) { 63 PostWrappedNonNestableTask(task_runner, Closure()); 64 } 65 } 66 67 void SequencedTaskTracker::RunTask(const Closure& task, int task_i) { 68 TaskStarted(task_i); 69 if (!task.is_null()) 70 task.Run(); 71 TaskEnded(task_i); 72 } 73 74 void SequencedTaskTracker::TaskPosted(int i) { 75 // Caller must own |lock_|. 76 events_.push_back(TaskEvent(i, TaskEvent::POST)); 77 } 78 79 void SequencedTaskTracker::TaskStarted(int i) { 80 AutoLock lock(lock_); 81 events_.push_back(TaskEvent(i, TaskEvent::START)); 82 } 83 84 void SequencedTaskTracker::TaskEnded(int i) { 85 AutoLock lock(lock_); 86 events_.push_back(TaskEvent(i, TaskEvent::END)); 87 ++task_end_count_; 88 task_end_cv_.Signal(); 89 } 90 91 const std::vector<TaskEvent>& 92 SequencedTaskTracker::GetTaskEvents() const { 93 return events_; 94 } 95 96 void SequencedTaskTracker::WaitForCompletedTasks(int count) { 97 AutoLock lock(lock_); 98 while (task_end_count_ < count) 99 task_end_cv_.Wait(); 100 } 101 102 SequencedTaskTracker::~SequencedTaskTracker() { 103 } 104 105 void PrintTo(const TaskEvent& event, std::ostream* os) { 106 *os << "(i=" << event.i << ", type="; 107 switch (event.type) { 108 case TaskEvent::POST: *os << "POST"; break; 109 case TaskEvent::START: *os << "START"; break; 110 case TaskEvent::END: *os << "END"; break; 111 } 112 *os << ")"; 113 } 114 115 namespace { 116 117 // Returns the task ordinals for the task event type |type| in the order that 118 // they were recorded. 119 std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events, 120 TaskEvent::Type type) { 121 std::vector<int> tasks; 122 std::vector<TaskEvent>::const_iterator event; 123 for (event = events.begin(); event != events.end(); ++event) { 124 if (event->type == type) 125 tasks.push_back(event->i); 126 } 127 return tasks; 128 } 129 130 // Returns all task events for task |task_i|. 131 std::vector<TaskEvent::Type> GetEventsForTask( 132 const std::vector<TaskEvent>& events, 133 int task_i) { 134 std::vector<TaskEvent::Type> task_event_orders; 135 std::vector<TaskEvent>::const_iterator event; 136 for (event = events.begin(); event != events.end(); ++event) { 137 if (event->i == task_i) 138 task_event_orders.push_back(event->type); 139 } 140 return task_event_orders; 141 } 142 143 // Checks that the task events for each task in |events| occur in the order 144 // {POST, START, END}, and that there is only one instance of each event type 145 // per task. 146 ::testing::AssertionResult CheckEventOrdersForEachTask( 147 const std::vector<TaskEvent>& events, 148 int task_count) { 149 std::vector<TaskEvent::Type> expected_order; 150 expected_order.push_back(TaskEvent::POST); 151 expected_order.push_back(TaskEvent::START); 152 expected_order.push_back(TaskEvent::END); 153 154 // This is O(n^2), but it runs fast enough currently so is not worth 155 // optimizing. 156 for (int i = 0; i < task_count; ++i) { 157 const std::vector<TaskEvent::Type> task_events = 158 GetEventsForTask(events, i); 159 if (task_events != expected_order) { 160 return ::testing::AssertionFailure() 161 << "Events for task " << i << " are out of order; expected: " 162 << ::testing::PrintToString(expected_order) << "; actual: " 163 << ::testing::PrintToString(task_events); 164 } 165 } 166 return ::testing::AssertionSuccess(); 167 } 168 169 // Checks that no two tasks were running at the same time. I.e. the only 170 // events allowed between the START and END of a task are the POSTs of other 171 // tasks. 172 ::testing::AssertionResult CheckNoTaskRunsOverlap( 173 const std::vector<TaskEvent>& events) { 174 // If > -1, we're currently inside a START, END pair. 175 int current_task_i = -1; 176 177 std::vector<TaskEvent>::const_iterator event; 178 for (event = events.begin(); event != events.end(); ++event) { 179 bool spurious_event_found = false; 180 181 if (current_task_i == -1) { // Not inside a START, END pair. 182 switch (event->type) { 183 case TaskEvent::POST: 184 break; 185 case TaskEvent::START: 186 current_task_i = event->i; 187 break; 188 case TaskEvent::END: 189 spurious_event_found = true; 190 break; 191 } 192 193 } else { // Inside a START, END pair. 194 bool interleaved_task_detected = false; 195 196 switch (event->type) { 197 case TaskEvent::POST: 198 if (event->i == current_task_i) 199 spurious_event_found = true; 200 break; 201 case TaskEvent::START: 202 interleaved_task_detected = true; 203 break; 204 case TaskEvent::END: 205 if (event->i != current_task_i) 206 interleaved_task_detected = true; 207 else 208 current_task_i = -1; 209 break; 210 } 211 212 if (interleaved_task_detected) { 213 return ::testing::AssertionFailure() 214 << "Found event " << ::testing::PrintToString(*event) 215 << " between START and END events for task " << current_task_i 216 << "; event dump: " << ::testing::PrintToString(events); 217 } 218 } 219 220 if (spurious_event_found) { 221 const int event_i = event - events.begin(); 222 return ::testing::AssertionFailure() 223 << "Spurious event " << ::testing::PrintToString(*event) 224 << " at position " << event_i << "; event dump: " 225 << ::testing::PrintToString(events); 226 } 227 } 228 229 return ::testing::AssertionSuccess(); 230 } 231 232 } // namespace 233 234 ::testing::AssertionResult CheckNonNestableInvariants( 235 const std::vector<TaskEvent>& events, 236 int task_count) { 237 const std::vector<int> post_order = 238 GetEventTypeOrder(events, TaskEvent::POST); 239 const std::vector<int> start_order = 240 GetEventTypeOrder(events, TaskEvent::START); 241 const std::vector<int> end_order = 242 GetEventTypeOrder(events, TaskEvent::END); 243 244 if (start_order != post_order) { 245 return ::testing::AssertionFailure() 246 << "Expected START order (which equals actual POST order): \n" 247 << ::testing::PrintToString(post_order) 248 << "\n Actual START order:\n" 249 << ::testing::PrintToString(start_order); 250 } 251 252 if (end_order != post_order) { 253 return ::testing::AssertionFailure() 254 << "Expected END order (which equals actual POST order): \n" 255 << ::testing::PrintToString(post_order) 256 << "\n Actual END order:\n" 257 << ::testing::PrintToString(end_order); 258 } 259 260 const ::testing::AssertionResult result = 261 CheckEventOrdersForEachTask(events, task_count); 262 if (!result) 263 return result; 264 265 return CheckNoTaskRunsOverlap(events); 266 } 267 268 } // namespace internal 269 270 } // namespace base 271