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(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(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(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(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(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(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(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(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 |