| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/task_scheduler/priority_queue.h" | 5 #include "base/task_scheduler/priority_queue.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/bind.h" | |
| 10 #include "base/bind_helpers.h" | |
| 11 #include "base/macros.h" | 9 #include "base/macros.h" |
| 12 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| 13 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 14 #include "base/synchronization/waitable_event.h" | 12 #include "base/synchronization/waitable_event.h" |
| 15 #include "base/task_scheduler/sequence.h" | 13 #include "base/task_scheduler/sequence.h" |
| 16 #include "base/task_scheduler/task.h" | 14 #include "base/task_scheduler/task.h" |
| 17 #include "base/task_scheduler/task_traits.h" | 15 #include "base/task_scheduler/task_traits.h" |
| 18 #include "base/task_scheduler/test_utils.h" | 16 #include "base/task_scheduler/test_utils.h" |
| 19 #include "base/threading/platform_thread.h" | 17 #include "base/threading/platform_thread.h" |
| 20 #include "base/threading/simple_thread.h" | 18 #include "base/threading/simple_thread.h" |
| 21 #include "base/time/time.h" | 19 #include "base/time/time.h" |
| 22 #include "testing/gmock/include/gmock/gmock.h" | |
| 23 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 24 | 21 |
| 25 namespace base { | 22 namespace base { |
| 26 namespace internal { | 23 namespace internal { |
| 27 | 24 |
| 28 namespace { | 25 namespace { |
| 29 | 26 |
| 30 class PriorityQueueCallbackMock { | |
| 31 public: | |
| 32 PriorityQueueCallbackMock() = default; | |
| 33 MOCK_METHOD0(WakeUp, void()); | |
| 34 | |
| 35 private: | |
| 36 DISALLOW_COPY_AND_ASSIGN(PriorityQueueCallbackMock); | |
| 37 }; | |
| 38 | |
| 39 class ThreadBeginningTransaction : public SimpleThread { | 27 class ThreadBeginningTransaction : public SimpleThread { |
| 40 public: | 28 public: |
| 41 explicit ThreadBeginningTransaction(PriorityQueue* priority_queue) | 29 explicit ThreadBeginningTransaction(PriorityQueue* priority_queue) |
| 42 : SimpleThread("ThreadBeginningTransaction"), | 30 : SimpleThread("ThreadBeginningTransaction"), |
| 43 priority_queue_(priority_queue), | 31 priority_queue_(priority_queue), |
| 44 transaction_began_(true, false) {} | 32 transaction_began_(true, false) {} |
| 45 | 33 |
| 46 // SimpleThread: | 34 // SimpleThread: |
| 47 void Run() override { | 35 void Run() override { |
| 48 std::unique_ptr<PriorityQueue::Transaction> transaction = | 36 std::unique_ptr<PriorityQueue::Transaction> transaction = |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); | 89 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); |
| 102 SequenceSortKey sort_key_c = sequence_c->GetSortKey(); | 90 SequenceSortKey sort_key_c = sequence_c->GetSortKey(); |
| 103 | 91 |
| 104 scoped_refptr<Sequence> sequence_d(new Sequence); | 92 scoped_refptr<Sequence> sequence_d(new Sequence); |
| 105 sequence_d->PushTask(WrapUnique( | 93 sequence_d->PushTask(WrapUnique( |
| 106 new Task(FROM_HERE, Closure(), | 94 new Task(FROM_HERE, Closure(), |
| 107 TaskTraits().WithPriority(TaskPriority::BACKGROUND)))); | 95 TaskTraits().WithPriority(TaskPriority::BACKGROUND)))); |
| 108 SequenceSortKey sort_key_d = sequence_d->GetSortKey(); | 96 SequenceSortKey sort_key_d = sequence_d->GetSortKey(); |
| 109 | 97 |
| 110 // Create a PriorityQueue and a Transaction. | 98 // Create a PriorityQueue and a Transaction. |
| 111 testing::StrictMock<PriorityQueueCallbackMock> mock; | 99 PriorityQueue pq; |
| 112 PriorityQueue pq(Bind(&PriorityQueueCallbackMock::WakeUp, Unretained(&mock))); | 100 auto transaction(pq.BeginTransaction()); |
| 113 std::unique_ptr<PriorityQueue::Transaction> transaction( | |
| 114 pq.BeginTransaction()); | |
| 115 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), | 101 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), |
| 116 transaction->Peek()); | 102 transaction->Peek()); |
| 117 | 103 |
| 118 // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the | 104 // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the |
| 119 // highest priority. | 105 // highest priority. |
| 120 transaction->Push(WrapUnique( | 106 transaction->Push(WrapUnique( |
| 121 new PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a))); | 107 new PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a))); |
| 122 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | 108 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( |
| 123 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a), | 109 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a), |
| 124 transaction->Peek()); | 110 transaction->Peek()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 // with the highest priority. | 151 // with the highest priority. |
| 166 transaction->Pop(); | 152 transaction->Pop(); |
| 167 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | 153 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( |
| 168 PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d), | 154 PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d), |
| 169 transaction->Peek()); | 155 transaction->Peek()); |
| 170 | 156 |
| 171 // Pop |sequence_d| from the PriorityQueue. It is now empty. | 157 // Pop |sequence_d| from the PriorityQueue. It is now empty. |
| 172 transaction->Pop(); | 158 transaction->Pop(); |
| 173 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), | 159 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), |
| 174 transaction->Peek()); | 160 transaction->Peek()); |
| 175 | |
| 176 // Expect 4 calls to mock.WakeUp() when the Transaction is destroyed. | |
| 177 EXPECT_CALL(mock, WakeUp()).Times(4); | |
| 178 transaction.reset(); | |
| 179 } | |
| 180 | |
| 181 TEST(TaskSchedulerPriorityQueueTest, PushNoWakeUpPopPeek) { | |
| 182 // Create test sequences. | |
| 183 scoped_refptr<Sequence> sequence_a(new Sequence); | |
| 184 sequence_a->PushTask(WrapUnique( | |
| 185 new Task(FROM_HERE, Closure(), | |
| 186 TaskTraits().WithPriority(TaskPriority::USER_VISIBLE)))); | |
| 187 SequenceSortKey sort_key_a = sequence_a->GetSortKey(); | |
| 188 | |
| 189 scoped_refptr<Sequence> sequence_b(new Sequence); | |
| 190 sequence_b->PushTask(WrapUnique( | |
| 191 new Task(FROM_HERE, Closure(), | |
| 192 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); | |
| 193 SequenceSortKey sort_key_b = sequence_b->GetSortKey(); | |
| 194 | |
| 195 scoped_refptr<Sequence> sequence_c(new Sequence); | |
| 196 sequence_c->PushTask(WrapUnique( | |
| 197 new Task(FROM_HERE, Closure(), | |
| 198 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); | |
| 199 SequenceSortKey sort_key_c = sequence_c->GetSortKey(); | |
| 200 | |
| 201 scoped_refptr<Sequence> sequence_d(new Sequence); | |
| 202 sequence_d->PushTask(WrapUnique( | |
| 203 new Task(FROM_HERE, Closure(), | |
| 204 TaskTraits().WithPriority(TaskPriority::BACKGROUND)))); | |
| 205 SequenceSortKey sort_key_d = sequence_d->GetSortKey(); | |
| 206 | |
| 207 // Create a PriorityQueue and a Transaction. | |
| 208 testing::StrictMock<PriorityQueueCallbackMock> mock; | |
| 209 PriorityQueue pq(Bind(&PriorityQueueCallbackMock::WakeUp, Unretained(&mock))); | |
| 210 std::unique_ptr<PriorityQueue::Transaction> transaction( | |
| 211 pq.BeginTransaction()); | |
| 212 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), | |
| 213 transaction->Peek()); | |
| 214 | |
| 215 // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the | |
| 216 // highest priority. | |
| 217 transaction->PushNoWakeUp(WrapUnique( | |
| 218 new PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a))); | |
| 219 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | |
| 220 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a), | |
| 221 transaction->Peek()); | |
| 222 | |
| 223 // Push |sequence_b| in the PriorityQueue. It becomes the sequence with the | |
| 224 // highest priority. | |
| 225 transaction->PushNoWakeUp(WrapUnique( | |
| 226 new PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b))); | |
| 227 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | |
| 228 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), | |
| 229 transaction->Peek()); | |
| 230 | |
| 231 // Push |sequence_c| in the PriorityQueue. |sequence_b| is still the sequence | |
| 232 // with the highest priority. | |
| 233 transaction->PushNoWakeUp(WrapUnique( | |
| 234 new PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c))); | |
| 235 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | |
| 236 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), | |
| 237 transaction->Peek()); | |
| 238 | |
| 239 // Push |sequence_d| in the PriorityQueue. |sequence_b| is still the sequence | |
| 240 // with the highest priority. | |
| 241 transaction->PushNoWakeUp(WrapUnique( | |
| 242 new PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d))); | |
| 243 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | |
| 244 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), | |
| 245 transaction->Peek()); | |
| 246 | |
| 247 // Pop |sequence_b| from the PriorityQueue. |sequence_c| becomes the sequence | |
| 248 // with the highest priority. | |
| 249 transaction->Pop(); | |
| 250 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | |
| 251 PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c), | |
| 252 transaction->Peek()); | |
| 253 | |
| 254 // Pop |sequence_c| from the PriorityQueue. |sequence_a| becomes the sequence | |
| 255 // with the highest priority. | |
| 256 transaction->Pop(); | |
| 257 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | |
| 258 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a), | |
| 259 transaction->Peek()); | |
| 260 | |
| 261 // Pop |sequence_a| from the PriorityQueue. |sequence_d| becomes the sequence | |
| 262 // with the highest priority. | |
| 263 transaction->Pop(); | |
| 264 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | |
| 265 PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d), | |
| 266 transaction->Peek()); | |
| 267 | |
| 268 // Pop |sequence_d| from the PriorityQueue. It is now empty. | |
| 269 transaction->Pop(); | |
| 270 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), | |
| 271 transaction->Peek()); | |
| 272 | |
| 273 // Expect no call to mock.WakeUp() when the Transaction is destroyed. | |
| 274 EXPECT_CALL(mock, WakeUp()).Times(0); | |
| 275 transaction.reset(); | |
| 276 } | 161 } |
| 277 | 162 |
| 278 // Check that creating Transactions on the same thread for 2 unrelated | 163 // Check that creating Transactions on the same thread for 2 unrelated |
| 279 // PriorityQueues causes a crash. | 164 // PriorityQueues causes a crash. |
| 280 TEST(TaskSchedulerPriorityQueueTest, IllegalTwoTransactionsSameThread) { | 165 TEST(TaskSchedulerPriorityQueueTest, IllegalTwoTransactionsSameThread) { |
| 281 PriorityQueue pq_a(Bind(&DoNothing)); | 166 PriorityQueue pq_a; |
| 282 PriorityQueue pq_b(Bind(&DoNothing)); | 167 PriorityQueue pq_b; |
| 283 | 168 |
| 284 EXPECT_DCHECK_DEATH( | 169 EXPECT_DCHECK_DEATH( |
| 285 { | 170 { |
| 286 std::unique_ptr<PriorityQueue::Transaction> transaction_a = | 171 std::unique_ptr<PriorityQueue::Transaction> transaction_a = |
| 287 pq_a.BeginTransaction(); | 172 pq_a.BeginTransaction(); |
| 288 std::unique_ptr<PriorityQueue::Transaction> transaction_b = | 173 std::unique_ptr<PriorityQueue::Transaction> transaction_b = |
| 289 pq_b.BeginTransaction(); | 174 pq_b.BeginTransaction(); |
| 290 }, | 175 }, |
| 291 ""); | 176 ""); |
| 292 } | 177 } |
| 293 | 178 |
| 294 // Check that there is no crash when Transactions are created on the same thread | 179 // Check that there is no crash when Transactions are created on the same thread |
| 295 // for 2 PriorityQueues which have a predecessor relationship. | 180 // for 2 PriorityQueues which have a predecessor relationship. |
| 296 TEST(TaskSchedulerPriorityQueueTest, LegalTwoTransactionsSameThread) { | 181 TEST(TaskSchedulerPriorityQueueTest, LegalTwoTransactionsSameThread) { |
| 297 PriorityQueue pq_a(Bind(&DoNothing)); | 182 PriorityQueue pq_a; |
| 298 PriorityQueue pq_b(Bind(&DoNothing), &pq_a); | 183 PriorityQueue pq_b(&pq_a); |
| 299 | 184 |
| 300 // This shouldn't crash. | 185 // This shouldn't crash. |
| 301 std::unique_ptr<PriorityQueue::Transaction> transaction_a = | 186 std::unique_ptr<PriorityQueue::Transaction> transaction_a = |
| 302 pq_a.BeginTransaction(); | 187 pq_a.BeginTransaction(); |
| 303 std::unique_ptr<PriorityQueue::Transaction> transaction_b = | 188 std::unique_ptr<PriorityQueue::Transaction> transaction_b = |
| 304 pq_b.BeginTransaction(); | 189 pq_b.BeginTransaction(); |
| 305 } | 190 } |
| 306 | 191 |
| 307 // Check that it is possible to begin multiple Transactions for the same | 192 // Check that it is possible to begin multiple Transactions for the same |
| 308 // PriorityQueue on different threads. The call to BeginTransaction() on the | 193 // PriorityQueue on different threads. The call to BeginTransaction() on the |
| 309 // second thread should block until the Transaction has ended on the first | 194 // second thread should block until the Transaction has ended on the first |
| 310 // thread. | 195 // thread. |
| 311 TEST(TaskSchedulerPriorityQueueTest, TwoTransactionsTwoThreads) { | 196 TEST(TaskSchedulerPriorityQueueTest, TwoTransactionsTwoThreads) { |
| 312 PriorityQueue pq(Bind(&DoNothing)); | 197 PriorityQueue pq; |
| 313 | 198 |
| 314 // Call BeginTransaction() on this thread and keep the Transaction alive. | 199 // Call BeginTransaction() on this thread and keep the Transaction alive. |
| 315 std::unique_ptr<PriorityQueue::Transaction> transaction = | 200 std::unique_ptr<PriorityQueue::Transaction> transaction = |
| 316 pq.BeginTransaction(); | 201 pq.BeginTransaction(); |
| 317 | 202 |
| 318 // Call BeginTransaction() on another thread. | 203 // Call BeginTransaction() on another thread. |
| 319 ThreadBeginningTransaction thread_beginning_transaction(&pq); | 204 ThreadBeginningTransaction thread_beginning_transaction(&pq); |
| 320 thread_beginning_transaction.Start(); | 205 thread_beginning_transaction.Start(); |
| 321 | 206 |
| 322 // After a few milliseconds, the call to BeginTransaction() on the other | 207 // After a few milliseconds, the call to BeginTransaction() on the other |
| 323 // thread should not have returned. | 208 // thread should not have returned. |
| 324 thread_beginning_transaction.ExpectTransactionDoesNotBegin(); | 209 thread_beginning_transaction.ExpectTransactionDoesNotBegin(); |
| 325 | 210 |
| 326 // End the Transaction on the current thread. | 211 // End the Transaction on the current thread. |
| 327 transaction.reset(); | 212 transaction.reset(); |
| 328 | 213 |
| 329 // The other thread should exit after its call to BeginTransaction() returns. | 214 // The other thread should exit after its call to BeginTransaction() returns. |
| 330 thread_beginning_transaction.Join(); | 215 thread_beginning_transaction.Join(); |
| 331 } | 216 } |
| 332 | 217 |
| 333 TEST(TaskSchedulerPriorityQueueTest, SequenceAndSortKeyIsNull) { | 218 TEST(TaskSchedulerPriorityQueueTest, SequenceAndSortKeyIsNull) { |
| 334 EXPECT_TRUE(PriorityQueue::SequenceAndSortKey().is_null()); | 219 EXPECT_TRUE(PriorityQueue::SequenceAndSortKey().is_null()); |
| 335 | 220 |
| 336 const PriorityQueue::SequenceAndSortKey non_null_sequence_andsort_key( | 221 const PriorityQueue::SequenceAndSortKey non_null_sequence_and_sort_key( |
| 337 make_scoped_refptr(new Sequence), | 222 make_scoped_refptr(new Sequence), |
| 338 SequenceSortKey(TaskPriority::USER_VISIBLE, TimeTicks())); | 223 SequenceSortKey(TaskPriority::USER_VISIBLE, TimeTicks())); |
| 339 EXPECT_FALSE(non_null_sequence_andsort_key.is_null()); | 224 EXPECT_FALSE(non_null_sequence_and_sort_key.is_null()); |
| 340 } | 225 } |
| 341 | 226 |
| 342 } // namespace internal | 227 } // namespace internal |
| 343 } // namespace base | 228 } // namespace base |
| OLD | NEW |