| 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/sequence.h" | 5 #include "base/task_scheduler/sequence.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| 11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/test/gtest_util.h" |
| 12 #include "base/time/time.h" | 13 #include "base/time/time.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 14 | 15 |
| 15 namespace base { | 16 namespace base { |
| 16 namespace internal { | 17 namespace internal { |
| 17 | 18 |
| 18 namespace { | 19 namespace { |
| 19 | 20 |
| 20 // A class that pushes a Task to a Sequence in its destructor. | |
| 21 class PushTaskInDestructor { | |
| 22 public: | |
| 23 explicit PushTaskInDestructor(scoped_refptr<Sequence> sequence) | |
| 24 : sequence_(std::move(sequence)) {} | |
| 25 PushTaskInDestructor(PushTaskInDestructor&&) = default; | |
| 26 PushTaskInDestructor& operator=(PushTaskInDestructor&&) = default; | |
| 27 | |
| 28 ~PushTaskInDestructor() { | |
| 29 // |sequence_| may be nullptr in a temporary instance of this class. | |
| 30 if (sequence_) { | |
| 31 EXPECT_FALSE(sequence_->PeekTask()); | |
| 32 sequence_->PushTask(WrapUnique( | |
| 33 new Task(FROM_HERE, Closure(), TaskTraits(), TimeDelta()))); | |
| 34 } | |
| 35 } | |
| 36 | |
| 37 private: | |
| 38 scoped_refptr<Sequence> sequence_; | |
| 39 | |
| 40 DISALLOW_COPY_AND_ASSIGN(PushTaskInDestructor); | |
| 41 }; | |
| 42 | |
| 43 void DoNothing(const PushTaskInDestructor&) {} | |
| 44 | 21 |
| 45 class TaskSchedulerSequenceTest : public testing::Test { | 22 class TaskSchedulerSequenceTest : public testing::Test { |
| 46 public: | 23 public: |
| 47 TaskSchedulerSequenceTest() | 24 TaskSchedulerSequenceTest() |
| 48 : task_a_owned_( | 25 : task_a_owned_( |
| 49 new Task(FROM_HERE, | 26 new Task(FROM_HERE, |
| 50 Closure(), | 27 Closure(), |
| 51 TaskTraits().WithPriority(TaskPriority::BACKGROUND), | 28 TaskTraits().WithPriority(TaskPriority::BACKGROUND), |
| 52 TimeDelta())), | 29 TimeDelta())), |
| 53 task_b_owned_( | 30 task_b_owned_( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 const Task* task_c_; | 69 const Task* task_c_; |
| 93 const Task* task_d_; | 70 const Task* task_d_; |
| 94 const Task* task_e_; | 71 const Task* task_e_; |
| 95 | 72 |
| 96 private: | 73 private: |
| 97 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSequenceTest); | 74 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSequenceTest); |
| 98 }; | 75 }; |
| 99 | 76 |
| 100 } // namespace | 77 } // namespace |
| 101 | 78 |
| 102 TEST_F(TaskSchedulerSequenceTest, PushPopPeek) { | 79 TEST_F(TaskSchedulerSequenceTest, PushTakeRemove) { |
| 103 scoped_refptr<Sequence> sequence(new Sequence); | 80 scoped_refptr<Sequence> sequence(new Sequence); |
| 104 | 81 |
| 105 // Push task A in the sequence. Its sequenced time should be updated and it | 82 // Push task A in the sequence. Its sequenced time should be updated and it |
| 106 // should be in front of the sequence. | 83 // should be in front of the sequence. |
| 107 EXPECT_TRUE(sequence->PushTask(std::move(task_a_owned_))); | 84 EXPECT_TRUE(sequence->PushTask(std::move(task_a_owned_))); |
| 108 EXPECT_FALSE(task_a_->sequenced_time.is_null()); | 85 EXPECT_FALSE(task_a_->sequenced_time.is_null()); |
| 109 EXPECT_EQ(task_a_, sequence->PeekTask()); | 86 EXPECT_EQ(task_a_->traits.priority(), |
| 87 sequence->GetFrontTaskTraits().priority()); |
| 110 | 88 |
| 111 // Push task B, C and D in the sequence. Their sequenced time should be | 89 // Push task B, C and D in the sequence. Their sequenced time should be |
| 112 // updated and task A should always remain in front of the sequence. | 90 // updated and task A should always remain in front of the sequence. |
| 113 EXPECT_FALSE(sequence->PushTask(std::move(task_b_owned_))); | 91 EXPECT_FALSE(sequence->PushTask(std::move(task_b_owned_))); |
| 114 EXPECT_FALSE(task_b_->sequenced_time.is_null()); | 92 EXPECT_FALSE(task_b_->sequenced_time.is_null()); |
| 115 EXPECT_EQ(task_a_, sequence->PeekTask()); | 93 EXPECT_EQ(task_a_->traits.priority(), |
| 94 sequence->GetFrontTaskTraits().priority()); |
| 116 | 95 |
| 117 EXPECT_FALSE(sequence->PushTask(std::move(task_c_owned_))); | 96 EXPECT_FALSE(sequence->PushTask(std::move(task_c_owned_))); |
| 118 EXPECT_FALSE(task_c_->sequenced_time.is_null()); | 97 EXPECT_FALSE(task_c_->sequenced_time.is_null()); |
| 119 EXPECT_EQ(task_a_, sequence->PeekTask()); | 98 EXPECT_EQ(task_a_->traits.priority(), |
| 99 sequence->GetFrontTaskTraits().priority()); |
| 120 | 100 |
| 121 EXPECT_FALSE(sequence->PushTask(std::move(task_d_owned_))); | 101 EXPECT_FALSE(sequence->PushTask(std::move(task_d_owned_))); |
| 122 EXPECT_FALSE(task_d_->sequenced_time.is_null()); | 102 EXPECT_FALSE(task_d_->sequenced_time.is_null()); |
| 123 EXPECT_EQ(task_a_, sequence->PeekTask()); | 103 EXPECT_EQ(task_a_->traits.priority(), |
| 104 sequence->GetFrontTaskTraits().priority()); |
| 124 | 105 |
| 125 // Pop task A. Task B should now be in front. | 106 // Take ownership of the task in front of the sequence. It should be task A. |
| 126 EXPECT_FALSE(sequence->PopTask()); | 107 EXPECT_EQ(task_a_, sequence->TakeTask().get()); |
| 127 EXPECT_EQ(task_b_, sequence->PeekTask()); | |
| 128 | 108 |
| 129 // Pop task B. Task C should now be in front. | 109 // Expect to find an empty slot in front of the sequence. |
| 130 EXPECT_FALSE(sequence->PopTask()); | 110 EXPECT_FALSE(sequence->TakeTask()); |
| 131 EXPECT_EQ(task_c_, sequence->PeekTask()); | |
| 132 | 111 |
| 133 // Pop task C. Task D should now be in front. | 112 // Remove the empty slot. Task B should now be in front. |
| 134 EXPECT_FALSE(sequence->PopTask()); | 113 EXPECT_FALSE(sequence->RemoveFrontSlot()); |
| 135 EXPECT_EQ(task_d_, sequence->PeekTask()); | 114 EXPECT_EQ(task_b_, sequence->TakeTask().get()); |
| 115 EXPECT_FALSE(sequence->TakeTask()); |
| 116 |
| 117 // Remove the empty slot. Task C should now be in front. |
| 118 EXPECT_FALSE(sequence->RemoveFrontSlot()); |
| 119 EXPECT_EQ(task_c_, sequence->TakeTask().get()); |
| 120 EXPECT_FALSE(sequence->TakeTask()); |
| 121 |
| 122 // Remove the empty slot. Task D should now be in front. |
| 123 EXPECT_FALSE(sequence->RemoveFrontSlot()); |
| 124 EXPECT_EQ(task_d_, sequence->TakeTask().get()); |
| 125 EXPECT_FALSE(sequence->TakeTask()); |
| 136 | 126 |
| 137 // Push task E in the sequence. Its sequenced time should be updated and | 127 // Push task E in the sequence. Its sequenced time should be updated and |
| 138 // task D should remain in front. | 128 // there should still be an empty slot in front of the sequence. |
| 139 EXPECT_FALSE(sequence->PushTask(std::move(task_e_owned_))); | 129 EXPECT_FALSE(sequence->PushTask(std::move(task_e_owned_))); |
| 140 EXPECT_FALSE(task_e_->sequenced_time.is_null()); | 130 EXPECT_FALSE(task_e_->sequenced_time.is_null()); |
| 141 EXPECT_EQ(task_d_, sequence->PeekTask()); | 131 EXPECT_FALSE(sequence->TakeTask()); |
| 142 | 132 |
| 143 // Pop task D. Task E should now be in front. | 133 // Remove the empty slot. Task E should now be in front. |
| 144 EXPECT_FALSE(sequence->PopTask()); | 134 EXPECT_FALSE(sequence->RemoveFrontSlot()); |
| 145 EXPECT_EQ(task_e_, sequence->PeekTask()); | 135 EXPECT_EQ(task_e_, sequence->TakeTask().get()); |
| 136 EXPECT_FALSE(sequence->TakeTask()); |
| 146 | 137 |
| 147 // Pop task E. The sequence should now be empty. | 138 // Remove the empty slot. The sequence should now be empty. |
| 148 EXPECT_TRUE(sequence->PopTask()); | 139 EXPECT_TRUE(sequence->RemoveFrontSlot()); |
| 149 EXPECT_EQ(nullptr, sequence->PeekTask()); | 140 EXPECT_FALSE(sequence->TakeTask()); |
| 150 } | 141 } |
| 151 | 142 |
| 152 TEST_F(TaskSchedulerSequenceTest, GetSortKey) { | 143 TEST_F(TaskSchedulerSequenceTest, GetSortKey) { |
| 153 scoped_refptr<Sequence> sequence(new Sequence); | 144 scoped_refptr<Sequence> sequence(new Sequence); |
| 154 | 145 |
| 155 // Push task A in the sequence. The highest priority is from task A | 146 // Push task A in the sequence. The highest priority is from task A |
| 156 // (BACKGROUND). Task A is in front of the sequence. | 147 // (BACKGROUND). Task A is in front of the sequence. |
| 157 sequence->PushTask(std::move(task_a_owned_)); | 148 sequence->PushTask(std::move(task_a_owned_)); |
| 158 EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_a_->sequenced_time), | 149 EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_a_->sequenced_time), |
| 159 sequence->GetSortKey()); | 150 sequence->GetSortKey()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 174 | 165 |
| 175 // Push task D in the sequence. The highest priority is from tasks C/D | 166 // Push task D in the sequence. The highest priority is from tasks C/D |
| 176 // (USER_BLOCKING). Task A is still in front of the sequence. | 167 // (USER_BLOCKING). Task A is still in front of the sequence. |
| 177 sequence->PushTask(std::move(task_d_owned_)); | 168 sequence->PushTask(std::move(task_d_owned_)); |
| 178 EXPECT_EQ( | 169 EXPECT_EQ( |
| 179 SequenceSortKey(TaskPriority::USER_BLOCKING, task_a_->sequenced_time), | 170 SequenceSortKey(TaskPriority::USER_BLOCKING, task_a_->sequenced_time), |
| 180 sequence->GetSortKey()); | 171 sequence->GetSortKey()); |
| 181 | 172 |
| 182 // Pop task A. The highest priority is still USER_BLOCKING. The task in front | 173 // Pop task A. The highest priority is still USER_BLOCKING. The task in front |
| 183 // of the sequence is now task B. | 174 // of the sequence is now task B. |
| 184 sequence->PopTask(); | 175 sequence->TakeTask(); |
| 176 sequence->RemoveFrontSlot(); |
| 185 EXPECT_EQ( | 177 EXPECT_EQ( |
| 186 SequenceSortKey(TaskPriority::USER_BLOCKING, task_b_->sequenced_time), | 178 SequenceSortKey(TaskPriority::USER_BLOCKING, task_b_->sequenced_time), |
| 187 sequence->GetSortKey()); | 179 sequence->GetSortKey()); |
| 188 | 180 |
| 189 // Pop task B. The highest priority is still USER_BLOCKING. The task in front | 181 // Pop task B. The highest priority is still USER_BLOCKING. The task in front |
| 190 // of the sequence is now task C. | 182 // of the sequence is now task C. |
| 191 sequence->PopTask(); | 183 sequence->TakeTask(); |
| 184 sequence->RemoveFrontSlot(); |
| 192 EXPECT_EQ( | 185 EXPECT_EQ( |
| 193 SequenceSortKey(TaskPriority::USER_BLOCKING, task_c_->sequenced_time), | 186 SequenceSortKey(TaskPriority::USER_BLOCKING, task_c_->sequenced_time), |
| 194 sequence->GetSortKey()); | 187 sequence->GetSortKey()); |
| 195 | 188 |
| 196 // Pop task C. The highest priority is still USER_BLOCKING. The task in front | 189 // Pop task C. The highest priority is still USER_BLOCKING. The task in front |
| 197 // of the sequence is now task D. | 190 // of the sequence is now task D. |
| 198 sequence->PopTask(); | 191 sequence->TakeTask(); |
| 192 sequence->RemoveFrontSlot(); |
| 199 EXPECT_EQ( | 193 EXPECT_EQ( |
| 200 SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time), | 194 SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time), |
| 201 sequence->GetSortKey()); | 195 sequence->GetSortKey()); |
| 202 | 196 |
| 203 // Push task E in the sequence. The highest priority is still USER_BLOCKING. | 197 // Push task E in the sequence. The highest priority is still USER_BLOCKING. |
| 204 // The task in front of the sequence is still task D. | 198 // The task in front of the sequence is still task D. |
| 205 sequence->PushTask(std::move(task_e_owned_)); | 199 sequence->PushTask(std::move(task_e_owned_)); |
| 206 EXPECT_EQ( | 200 EXPECT_EQ( |
| 207 SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time), | 201 SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time), |
| 208 sequence->GetSortKey()); | 202 sequence->GetSortKey()); |
| 209 | 203 |
| 210 // Pop task D. The highest priority is now from task E (BACKGROUND). The | 204 // Pop task D. The highest priority is now from task E (BACKGROUND). The |
| 211 // task in front of the sequence is now task E. | 205 // task in front of the sequence is now task E. |
| 212 sequence->PopTask(); | 206 sequence->TakeTask(); |
| 207 sequence->RemoveFrontSlot(); |
| 213 EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_e_->sequenced_time), | 208 EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_e_->sequenced_time), |
| 214 sequence->GetSortKey()); | 209 sequence->GetSortKey()); |
| 215 } | 210 } |
| 216 | 211 |
| 217 TEST_F(TaskSchedulerSequenceTest, CanPushTaskInTaskDestructor) { | 212 // Verify that a DCHECK fires if RemoveFrontSlot() is called on a sequence whose |
| 213 // front slot isn't empty. |
| 214 TEST_F(TaskSchedulerSequenceTest, RemoveNonEmptyFrontSlot) { |
| 218 scoped_refptr<Sequence> sequence(new Sequence); | 215 scoped_refptr<Sequence> sequence(new Sequence); |
| 219 sequence->PushTask(MakeUnique<Task>( | 216 sequence->PushTask( |
| 220 FROM_HERE, Bind(&DoNothing, PushTaskInDestructor(sequence)), TaskTraits(), | 217 MakeUnique<Task>(FROM_HERE, Bind(&DoNothing), TaskTraits(), TimeDelta())); |
| 221 TimeDelta())); | |
| 222 | 218 |
| 223 // PushTask() is invoked on |sequence| when the popped Task is destroyed. If | 219 EXPECT_DCHECK_DEATH({ sequence->RemoveFrontSlot(); }); |
| 224 // PopTask() destroys the Task outside the scope of its lock as expected, no | |
| 225 // deadlock will occur when PushTask() tries to acquire the Sequence's lock. | |
| 226 sequence->PopTask(); | |
| 227 | |
| 228 // Verify that |sequence| contains exactly one Task. | |
| 229 EXPECT_TRUE(sequence->PeekTask()); | |
| 230 EXPECT_TRUE(sequence->PopTask()); | |
| 231 } | 220 } |
| 232 | 221 |
| 233 } // namespace internal | 222 } // namespace internal |
| 234 } // namespace base | 223 } // namespace base |
| OLD | NEW |