| 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> |
| 8 |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 9 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/memory/ptr_util.h" |
| 10 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "base/synchronization/waitable_event.h" | 14 #include "base/synchronization/waitable_event.h" |
| 13 #include "base/task_scheduler/sequence.h" | 15 #include "base/task_scheduler/sequence.h" |
| 14 #include "base/task_scheduler/task.h" | 16 #include "base/task_scheduler/task.h" |
| 15 #include "base/task_scheduler/task_traits.h" | 17 #include "base/task_scheduler/task_traits.h" |
| 16 #include "base/task_scheduler/test_utils.h" | 18 #include "base/task_scheduler/test_utils.h" |
| 17 #include "base/threading/platform_thread.h" | 19 #include "base/threading/platform_thread.h" |
| 18 #include "base/threading/simple_thread.h" | 20 #include "base/threading/simple_thread.h" |
| 19 #include "base/time/time.h" | 21 #include "base/time/time.h" |
| 20 #include "testing/gmock/include/gmock/gmock.h" | 22 #include "testing/gmock/include/gmock/gmock.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 36 | 38 |
| 37 class ThreadBeginningTransaction : public SimpleThread { | 39 class ThreadBeginningTransaction : public SimpleThread { |
| 38 public: | 40 public: |
| 39 explicit ThreadBeginningTransaction(PriorityQueue* priority_queue) | 41 explicit ThreadBeginningTransaction(PriorityQueue* priority_queue) |
| 40 : SimpleThread("ThreadBeginningTransaction"), | 42 : SimpleThread("ThreadBeginningTransaction"), |
| 41 priority_queue_(priority_queue), | 43 priority_queue_(priority_queue), |
| 42 transaction_began_(true, false) {} | 44 transaction_began_(true, false) {} |
| 43 | 45 |
| 44 // SimpleThread: | 46 // SimpleThread: |
| 45 void Run() override { | 47 void Run() override { |
| 46 scoped_ptr<PriorityQueue::Transaction> transaction = | 48 std::unique_ptr<PriorityQueue::Transaction> transaction = |
| 47 priority_queue_->BeginTransaction(); | 49 priority_queue_->BeginTransaction(); |
| 48 transaction_began_.Signal(); | 50 transaction_began_.Signal(); |
| 49 } | 51 } |
| 50 | 52 |
| 51 void ExpectTransactionDoesNotBegin() { | 53 void ExpectTransactionDoesNotBegin() { |
| 52 // After a few milliseconds, the call to BeginTransaction() should not have | 54 // After a few milliseconds, the call to BeginTransaction() should not have |
| 53 // returned. | 55 // returned. |
| 54 EXPECT_FALSE( | 56 EXPECT_FALSE( |
| 55 transaction_began_.TimedWait(TimeDelta::FromMilliseconds(250))); | 57 transaction_began_.TimedWait(TimeDelta::FromMilliseconds(250))); |
| 56 } | 58 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 75 do { \ | 77 do { \ |
| 76 SCOPED_TRACE(""); \ | 78 SCOPED_TRACE(""); \ |
| 77 ExpectSequenceAndSortKeyEq(expected, actual); \ | 79 ExpectSequenceAndSortKeyEq(expected, actual); \ |
| 78 } while (false) | 80 } while (false) |
| 79 | 81 |
| 80 } // namespace | 82 } // namespace |
| 81 | 83 |
| 82 TEST(TaskSchedulerPriorityQueueTest, PushPopPeek) { | 84 TEST(TaskSchedulerPriorityQueueTest, PushPopPeek) { |
| 83 // Create test sequences. | 85 // Create test sequences. |
| 84 scoped_refptr<Sequence> sequence_a(new Sequence); | 86 scoped_refptr<Sequence> sequence_a(new Sequence); |
| 85 sequence_a->PushTask(make_scoped_ptr( | 87 sequence_a->PushTask(base::WrapUnique( |
| 86 new Task(FROM_HERE, Closure(), | 88 new Task(FROM_HERE, Closure(), |
| 87 TaskTraits().WithPriority(TaskPriority::USER_VISIBLE)))); | 89 TaskTraits().WithPriority(TaskPriority::USER_VISIBLE)))); |
| 88 SequenceSortKey sort_key_a = sequence_a->GetSortKey(); | 90 SequenceSortKey sort_key_a = sequence_a->GetSortKey(); |
| 89 | 91 |
| 90 scoped_refptr<Sequence> sequence_b(new Sequence); | 92 scoped_refptr<Sequence> sequence_b(new Sequence); |
| 91 sequence_b->PushTask(make_scoped_ptr( | 93 sequence_b->PushTask(base::WrapUnique( |
| 92 new Task(FROM_HERE, Closure(), | 94 new Task(FROM_HERE, Closure(), |
| 93 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); | 95 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); |
| 94 SequenceSortKey sort_key_b = sequence_b->GetSortKey(); | 96 SequenceSortKey sort_key_b = sequence_b->GetSortKey(); |
| 95 | 97 |
| 96 scoped_refptr<Sequence> sequence_c(new Sequence); | 98 scoped_refptr<Sequence> sequence_c(new Sequence); |
| 97 sequence_c->PushTask(make_scoped_ptr( | 99 sequence_c->PushTask(base::WrapUnique( |
| 98 new Task(FROM_HERE, Closure(), | 100 new Task(FROM_HERE, Closure(), |
| 99 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); | 101 TaskTraits().WithPriority(TaskPriority::USER_BLOCKING)))); |
| 100 SequenceSortKey sort_key_c = sequence_c->GetSortKey(); | 102 SequenceSortKey sort_key_c = sequence_c->GetSortKey(); |
| 101 | 103 |
| 102 scoped_refptr<Sequence> sequence_d(new Sequence); | 104 scoped_refptr<Sequence> sequence_d(new Sequence); |
| 103 sequence_d->PushTask(make_scoped_ptr( | 105 sequence_d->PushTask(base::WrapUnique( |
| 104 new Task(FROM_HERE, Closure(), | 106 new Task(FROM_HERE, Closure(), |
| 105 TaskTraits().WithPriority(TaskPriority::BACKGROUND)))); | 107 TaskTraits().WithPriority(TaskPriority::BACKGROUND)))); |
| 106 SequenceSortKey sort_key_d = sequence_d->GetSortKey(); | 108 SequenceSortKey sort_key_d = sequence_d->GetSortKey(); |
| 107 | 109 |
| 108 // Create a PriorityQueue and a Transaction. | 110 // Create a PriorityQueue and a Transaction. |
| 109 testing::StrictMock<PriorityQueueCallbackMock> mock; | 111 testing::StrictMock<PriorityQueueCallbackMock> mock; |
| 110 PriorityQueue pq( | 112 PriorityQueue pq( |
| 111 Bind(&PriorityQueueCallbackMock::SequenceInsertedInPriorityQueue, | 113 Bind(&PriorityQueueCallbackMock::SequenceInsertedInPriorityQueue, |
| 112 Unretained(&mock))); | 114 Unretained(&mock))); |
| 113 scoped_ptr<PriorityQueue::Transaction> transaction(pq.BeginTransaction()); | 115 std::unique_ptr<PriorityQueue::Transaction> transaction( |
| 116 pq.BeginTransaction()); |
| 114 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), | 117 EXPECT_SEQUENCE_AND_SORT_KEY_EQ(PriorityQueue::SequenceAndSortKey(), |
| 115 transaction->Peek()); | 118 transaction->Peek()); |
| 116 | 119 |
| 117 // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the | 120 // Push |sequence_a| in the PriorityQueue. It becomes the sequence with the |
| 118 // highest priority. | 121 // highest priority. |
| 119 transaction->Push(make_scoped_ptr( | 122 transaction->Push(base::WrapUnique( |
| 120 new PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a))); | 123 new PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a))); |
| 121 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | 124 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( |
| 122 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a), | 125 PriorityQueue::SequenceAndSortKey(sequence_a, sort_key_a), |
| 123 transaction->Peek()); | 126 transaction->Peek()); |
| 124 | 127 |
| 125 // Push |sequence_b| in the PriorityQueue. It becomes the sequence with the | 128 // Push |sequence_b| in the PriorityQueue. It becomes the sequence with the |
| 126 // highest priority. | 129 // highest priority. |
| 127 transaction->Push(make_scoped_ptr( | 130 transaction->Push(base::WrapUnique( |
| 128 new PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b))); | 131 new PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b))); |
| 129 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | 132 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( |
| 130 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), | 133 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), |
| 131 transaction->Peek()); | 134 transaction->Peek()); |
| 132 | 135 |
| 133 // Push |sequence_c| in the PriorityQueue. |sequence_b| is still the sequence | 136 // Push |sequence_c| in the PriorityQueue. |sequence_b| is still the sequence |
| 134 // with the highest priority. | 137 // with the highest priority. |
| 135 transaction->Push(make_scoped_ptr( | 138 transaction->Push(base::WrapUnique( |
| 136 new PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c))); | 139 new PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c))); |
| 137 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | 140 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( |
| 138 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), | 141 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), |
| 139 transaction->Peek()); | 142 transaction->Peek()); |
| 140 | 143 |
| 141 // Push |sequence_d| in the PriorityQueue. |sequence_b| is still the sequence | 144 // Push |sequence_d| in the PriorityQueue. |sequence_b| is still the sequence |
| 142 // with the highest priority. | 145 // with the highest priority. |
| 143 transaction->Push(make_scoped_ptr( | 146 transaction->Push(base::WrapUnique( |
| 144 new PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d))); | 147 new PriorityQueue::SequenceAndSortKey(sequence_d, sort_key_d))); |
| 145 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | 148 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( |
| 146 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), | 149 PriorityQueue::SequenceAndSortKey(sequence_b, sort_key_b), |
| 147 transaction->Peek()); | 150 transaction->Peek()); |
| 148 | 151 |
| 149 // Pop |sequence_b| from the PriorityQueue. |sequence_c| becomes the sequence | 152 // Pop |sequence_b| from the PriorityQueue. |sequence_c| becomes the sequence |
| 150 // with the highest priority. | 153 // with the highest priority. |
| 151 transaction->Pop(); | 154 transaction->Pop(); |
| 152 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( | 155 EXPECT_SEQUENCE_AND_SORT_KEY_EQ( |
| 153 PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c), | 156 PriorityQueue::SequenceAndSortKey(sequence_c, sort_key_c), |
| (...skipping 25 matching lines...) Expand all Loading... |
| 179 } | 182 } |
| 180 | 183 |
| 181 // Check that creating Transactions on the same thread for 2 unrelated | 184 // Check that creating Transactions on the same thread for 2 unrelated |
| 182 // PriorityQueues causes a crash. | 185 // PriorityQueues causes a crash. |
| 183 TEST(TaskSchedulerPriorityQueueTest, IllegalTwoTransactionsSameThread) { | 186 TEST(TaskSchedulerPriorityQueueTest, IllegalTwoTransactionsSameThread) { |
| 184 PriorityQueue pq_a(Bind(&DoNothing)); | 187 PriorityQueue pq_a(Bind(&DoNothing)); |
| 185 PriorityQueue pq_b(Bind(&DoNothing)); | 188 PriorityQueue pq_b(Bind(&DoNothing)); |
| 186 | 189 |
| 187 EXPECT_DCHECK_DEATH( | 190 EXPECT_DCHECK_DEATH( |
| 188 { | 191 { |
| 189 scoped_ptr<PriorityQueue::Transaction> transaction_a = | 192 std::unique_ptr<PriorityQueue::Transaction> transaction_a = |
| 190 pq_a.BeginTransaction(); | 193 pq_a.BeginTransaction(); |
| 191 scoped_ptr<PriorityQueue::Transaction> transaction_b = | 194 std::unique_ptr<PriorityQueue::Transaction> transaction_b = |
| 192 pq_b.BeginTransaction(); | 195 pq_b.BeginTransaction(); |
| 193 }, | 196 }, |
| 194 ""); | 197 ""); |
| 195 } | 198 } |
| 196 | 199 |
| 197 // Check that there is no crash when Transactions are created on the same thread | 200 // Check that there is no crash when Transactions are created on the same thread |
| 198 // for 2 PriorityQueues which have a predecessor relationship. | 201 // for 2 PriorityQueues which have a predecessor relationship. |
| 199 TEST(TaskSchedulerPriorityQueueTest, LegalTwoTransactionsSameThread) { | 202 TEST(TaskSchedulerPriorityQueueTest, LegalTwoTransactionsSameThread) { |
| 200 PriorityQueue pq_a(Bind(&DoNothing)); | 203 PriorityQueue pq_a(Bind(&DoNothing)); |
| 201 PriorityQueue pq_b(Bind(&DoNothing), &pq_a); | 204 PriorityQueue pq_b(Bind(&DoNothing), &pq_a); |
| 202 | 205 |
| 203 // This shouldn't crash. | 206 // This shouldn't crash. |
| 204 scoped_ptr<PriorityQueue::Transaction> transaction_a = | 207 std::unique_ptr<PriorityQueue::Transaction> transaction_a = |
| 205 pq_a.BeginTransaction(); | 208 pq_a.BeginTransaction(); |
| 206 scoped_ptr<PriorityQueue::Transaction> transaction_b = | 209 std::unique_ptr<PriorityQueue::Transaction> transaction_b = |
| 207 pq_b.BeginTransaction(); | 210 pq_b.BeginTransaction(); |
| 208 } | 211 } |
| 209 | 212 |
| 210 // Check that it is possible to begin multiple Transactions for the same | 213 // Check that it is possible to begin multiple Transactions for the same |
| 211 // PriorityQueue on different threads. The call to BeginTransaction() on the | 214 // PriorityQueue on different threads. The call to BeginTransaction() on the |
| 212 // second thread should block until the Transaction has ended on the first | 215 // second thread should block until the Transaction has ended on the first |
| 213 // thread. | 216 // thread. |
| 214 TEST(TaskSchedulerPriorityQueueTest, TwoTransactionsTwoThreads) { | 217 TEST(TaskSchedulerPriorityQueueTest, TwoTransactionsTwoThreads) { |
| 215 PriorityQueue pq(Bind(&DoNothing)); | 218 PriorityQueue pq(Bind(&DoNothing)); |
| 216 | 219 |
| 217 // Call BeginTransaction() on this thread and keep the Transaction alive. | 220 // Call BeginTransaction() on this thread and keep the Transaction alive. |
| 218 scoped_ptr<PriorityQueue::Transaction> transaction = pq.BeginTransaction(); | 221 std::unique_ptr<PriorityQueue::Transaction> transaction = |
| 222 pq.BeginTransaction(); |
| 219 | 223 |
| 220 // Call BeginTransaction() on another thread. | 224 // Call BeginTransaction() on another thread. |
| 221 ThreadBeginningTransaction thread_beginning_transaction(&pq); | 225 ThreadBeginningTransaction thread_beginning_transaction(&pq); |
| 222 thread_beginning_transaction.Start(); | 226 thread_beginning_transaction.Start(); |
| 223 | 227 |
| 224 // After a few milliseconds, the call to BeginTransaction() on the other | 228 // After a few milliseconds, the call to BeginTransaction() on the other |
| 225 // thread should not have returned. | 229 // thread should not have returned. |
| 226 thread_beginning_transaction.ExpectTransactionDoesNotBegin(); | 230 thread_beginning_transaction.ExpectTransactionDoesNotBegin(); |
| 227 | 231 |
| 228 // End the Transaction on the current thread. | 232 // End the Transaction on the current thread. |
| 229 transaction.reset(); | 233 transaction.reset(); |
| 230 | 234 |
| 231 // The other thread should exit after its call to BeginTransaction() returns. | 235 // The other thread should exit after its call to BeginTransaction() returns. |
| 232 thread_beginning_transaction.Join(); | 236 thread_beginning_transaction.Join(); |
| 233 } | 237 } |
| 234 | 238 |
| 235 TEST(TaskSchedulerPriorityQueueTest, SequenceAndSortKeyIsNull) { | 239 TEST(TaskSchedulerPriorityQueueTest, SequenceAndSortKeyIsNull) { |
| 236 EXPECT_TRUE(PriorityQueue::SequenceAndSortKey().is_null()); | 240 EXPECT_TRUE(PriorityQueue::SequenceAndSortKey().is_null()); |
| 237 | 241 |
| 238 const PriorityQueue::SequenceAndSortKey non_null_sequence_andsort_key( | 242 const PriorityQueue::SequenceAndSortKey non_null_sequence_andsort_key( |
| 239 make_scoped_refptr(new Sequence), | 243 make_scoped_refptr(new Sequence), |
| 240 SequenceSortKey(TaskPriority::USER_VISIBLE, TimeTicks())); | 244 SequenceSortKey(TaskPriority::USER_VISIBLE, TimeTicks())); |
| 241 EXPECT_FALSE(non_null_sequence_andsort_key.is_null()); | 245 EXPECT_FALSE(non_null_sequence_andsort_key.is_null()); |
| 242 } | 246 } |
| 243 | 247 |
| 244 } // namespace internal | 248 } // namespace internal |
| 245 } // namespace base | 249 } // namespace base |
| OLD | NEW |