| 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/scheduler_worker_thread.h" | 5 #include "base/task_scheduler/scheduler_worker_thread.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
| 16 #include "base/synchronization/condition_variable.h" | 16 #include "base/synchronization/condition_variable.h" |
| 17 #include "base/task_scheduler/scheduler_lock.h" | 17 #include "base/task_scheduler/scheduler_lock.h" |
| 18 #include "base/task_scheduler/sequence.h" | 18 #include "base/task_scheduler/sequence.h" |
| 19 #include "base/task_scheduler/task.h" | 19 #include "base/task_scheduler/task.h" |
| 20 #include "base/task_scheduler/task_tracker.h" | 20 #include "base/task_scheduler/task_tracker.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 | 22 |
| 23 namespace base { | 23 namespace base { |
| 24 namespace internal { | 24 namespace internal { |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 const size_t kNumSequencesPerTest = 150; | 27 const size_t kNumSequencesPerTest = 150; |
| 28 | 28 |
| 29 // The test parameter is the number of Tasks per Sequence returned by GetWork(). | 29 // The test parameter is the number of Tasks per Sequence returned by GetWork(). |
| 30 class TaskSchedulerWorkerThreadTest : public testing::TestWithParam<size_t>, | 30 class TaskSchedulerWorkerThreadTest : public testing::TestWithParam<size_t> { |
| 31 public SchedulerWorkerThread::Delegate { | |
| 32 protected: | 31 protected: |
| 33 TaskSchedulerWorkerThreadTest() | 32 TaskSchedulerWorkerThreadTest() |
| 34 : main_entry_called_(true, false), | 33 : main_entry_called_(true, false), |
| 35 num_get_work_cv_(lock_.CreateConditionVariable()) {} | 34 num_get_work_cv_(lock_.CreateConditionVariable()) {} |
| 36 | 35 |
| 37 void SetUp() override { | 36 void SetUp() override { |
| 38 worker_thread_ = SchedulerWorkerThread::CreateSchedulerWorkerThread( | 37 worker_thread_ = SchedulerWorkerThread::Create( |
| 39 ThreadPriority::NORMAL, this, &task_tracker_); | 38 ThreadPriority::NORMAL, |
| 39 WrapUnique(new TestSchedulerWorkerThreadDelegate(this)), |
| 40 &task_tracker_); |
| 40 ASSERT_TRUE(worker_thread_); | 41 ASSERT_TRUE(worker_thread_); |
| 41 main_entry_called_.Wait(); | 42 main_entry_called_.Wait(); |
| 42 } | 43 } |
| 43 | 44 |
| 44 void TearDown() override { | 45 void TearDown() override { |
| 45 worker_thread_->JoinForTesting(); | 46 worker_thread_->JoinForTesting(); |
| 46 } | 47 } |
| 47 | 48 |
| 48 size_t TasksPerSequence() const { return GetParam(); } | 49 size_t TasksPerSequence() const { return GetParam(); } |
| 49 | 50 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 76 } | 77 } |
| 77 | 78 |
| 78 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { | 79 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { |
| 79 AutoSchedulerLock auto_lock(lock_); | 80 AutoSchedulerLock auto_lock(lock_); |
| 80 return re_enqueued_sequences_; | 81 return re_enqueued_sequences_; |
| 81 } | 82 } |
| 82 | 83 |
| 83 std::unique_ptr<SchedulerWorkerThread> worker_thread_; | 84 std::unique_ptr<SchedulerWorkerThread> worker_thread_; |
| 84 | 85 |
| 85 private: | 86 private: |
| 86 // SchedulerWorkerThread::Delegate: | 87 class TestSchedulerWorkerThreadDelegate |
| 87 void OnMainEntry() override { | 88 : public SchedulerWorkerThread::Delegate { |
| 88 // Without this |auto_lock|, OnMainEntry() could be called twice without | 89 public: |
| 89 // generating an error. | 90 TestSchedulerWorkerThreadDelegate(TaskSchedulerWorkerThreadTest* outer) |
| 90 AutoSchedulerLock auto_lock(lock_); | 91 : outer_(outer) {} |
| 91 EXPECT_FALSE(main_entry_called_.IsSignaled()); | |
| 92 main_entry_called_.Signal(); | |
| 93 } | |
| 94 | 92 |
| 95 scoped_refptr<Sequence> GetWork( | 93 // SchedulerWorkerThread::Delegate: |
| 96 SchedulerWorkerThread* worker_thread) override { | 94 void OnMainEntry() override { |
| 97 EXPECT_EQ(worker_thread_.get(), worker_thread); | 95 // Without synchronization, OnMainEntry() could be called twice without |
| 98 | 96 // generating an error. |
| 99 { | 97 AutoSchedulerLock auto_lock(outer_->lock_); |
| 100 AutoSchedulerLock auto_lock(lock_); | 98 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); |
| 101 | 99 outer_->main_entry_called_.Signal(); |
| 102 // Increment the number of times that this method has been called. | |
| 103 ++num_get_work_; | |
| 104 num_get_work_cv_->Signal(); | |
| 105 | |
| 106 // Verify that this method isn't called more times than expected. | |
| 107 EXPECT_LE(num_get_work_, max_get_work_); | |
| 108 | |
| 109 // Check if a Sequence should be returned. | |
| 110 if (num_sequences_to_create_ == 0) | |
| 111 return nullptr; | |
| 112 --num_sequences_to_create_; | |
| 113 } | 100 } |
| 114 | 101 |
| 115 // Create a Sequence with TasksPerSequence() Tasks. | 102 scoped_refptr<Sequence> GetWork( |
| 116 scoped_refptr<Sequence> sequence(new Sequence); | 103 SchedulerWorkerThread* worker_thread) override { |
| 117 for (size_t i = 0; i < TasksPerSequence(); ++i) { | 104 EXPECT_EQ(outer_->worker_thread_.get(), worker_thread); |
| 118 std::unique_ptr<Task> task(new Task( | 105 |
| 119 FROM_HERE, Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, | 106 { |
| 120 Unretained(this)), | 107 AutoSchedulerLock auto_lock(outer_->lock_); |
| 121 TaskTraits(), TimeTicks())); | 108 |
| 122 EXPECT_TRUE(task_tracker_.WillPostTask(task.get())); | 109 // Increment the number of times that this method has been called. |
| 123 sequence->PushTask(std::move(task)); | 110 ++outer_->num_get_work_; |
| 111 outer_->num_get_work_cv_->Signal(); |
| 112 |
| 113 // Verify that this method isn't called more times than expected. |
| 114 EXPECT_LE(outer_->num_get_work_, outer_->max_get_work_); |
| 115 |
| 116 // Check if a Sequence should be returned. |
| 117 if (outer_->num_sequences_to_create_ == 0) |
| 118 return nullptr; |
| 119 --outer_->num_sequences_to_create_; |
| 120 } |
| 121 |
| 122 // Create a Sequence with TasksPerSequence() Tasks. |
| 123 scoped_refptr<Sequence> sequence(new Sequence); |
| 124 for (size_t i = 0; i < outer_->TasksPerSequence(); ++i) { |
| 125 std::unique_ptr<Task> task(new Task( |
| 126 FROM_HERE, Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, |
| 127 Unretained(outer_)), |
| 128 TaskTraits(), TimeTicks())); |
| 129 EXPECT_TRUE(outer_->task_tracker_.WillPostTask(task.get())); |
| 130 sequence->PushTask(std::move(task)); |
| 131 } |
| 132 |
| 133 { |
| 134 // Add the Sequence to the vector of created Sequences. |
| 135 AutoSchedulerLock auto_lock(outer_->lock_); |
| 136 outer_->created_sequences_.push_back(sequence); |
| 137 } |
| 138 |
| 139 return sequence; |
| 124 } | 140 } |
| 125 | 141 |
| 126 { | 142 // This override verifies that |sequence| contains the expected number of |
| 127 // Add the Sequence to the vector of created Sequences. | 143 // Tasks and adds it to |enqueued_sequences_|. Unlike a normal |
| 128 AutoSchedulerLock auto_lock(lock_); | 144 // EnqueueSequence implementation, it doesn't reinsert |sequence| into a |
| 129 created_sequences_.push_back(sequence); | 145 // queue for further execution. |
| 146 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { |
| 147 EXPECT_GT(outer_->TasksPerSequence(), 1U); |
| 148 |
| 149 // Verify that |sequence| contains TasksPerSequence() - 1 Tasks. |
| 150 for (size_t i = 0; i < outer_->TasksPerSequence() - 1; ++i) { |
| 151 EXPECT_TRUE(sequence->PeekTask()); |
| 152 sequence->PopTask(); |
| 153 } |
| 154 EXPECT_FALSE(sequence->PeekTask()); |
| 155 |
| 156 // Add |sequence| to |re_enqueued_sequences_|. |
| 157 AutoSchedulerLock auto_lock(outer_->lock_); |
| 158 outer_->re_enqueued_sequences_.push_back(std::move(sequence)); |
| 159 EXPECT_LE(outer_->re_enqueued_sequences_.size(), |
| 160 outer_->created_sequences_.size()); |
| 130 } | 161 } |
| 131 | 162 |
| 132 return sequence; | 163 private: |
| 133 } | 164 TaskSchedulerWorkerThreadTest* outer_; |
| 134 | 165 }; |
| 135 // This override verifies that |sequence| contains the expected number of | |
| 136 // Tasks and adds it to |re_enqueued_sequences_|. Unlike a normal | |
| 137 // ReEnqueueSequence implementation, it doesn't reinsert |sequence| into a | |
| 138 // queue for further execution. | |
| 139 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { | |
| 140 EXPECT_GT(TasksPerSequence(), 1U); | |
| 141 | |
| 142 // Verify that |sequence| contains TasksPerSequence() - 1 Tasks. | |
| 143 for (size_t i = 0; i < TasksPerSequence() - 1; ++i) { | |
| 144 EXPECT_TRUE(sequence->PeekTask()); | |
| 145 sequence->PopTask(); | |
| 146 } | |
| 147 EXPECT_FALSE(sequence->PeekTask()); | |
| 148 | |
| 149 // Add |sequence| to |re_enqueued_sequences_|. | |
| 150 AutoSchedulerLock auto_lock(lock_); | |
| 151 re_enqueued_sequences_.push_back(std::move(sequence)); | |
| 152 EXPECT_LE(re_enqueued_sequences_.size(), created_sequences_.size()); | |
| 153 } | |
| 154 | 166 |
| 155 void RunTaskCallback() { | 167 void RunTaskCallback() { |
| 156 AutoSchedulerLock auto_lock(lock_); | 168 AutoSchedulerLock auto_lock(lock_); |
| 157 ++num_run_tasks_; | 169 ++num_run_tasks_; |
| 158 EXPECT_LE(num_run_tasks_, created_sequences_.size()); | 170 EXPECT_LE(num_run_tasks_, created_sequences_.size()); |
| 159 } | 171 } |
| 160 | 172 |
| 161 TaskTracker task_tracker_; | 173 TaskTracker task_tracker_; |
| 162 | 174 |
| 163 // Synchronizes access to all members below. | 175 // Synchronizes access to all members below. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, | 267 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, |
| 256 TaskSchedulerWorkerThreadTest, | 268 TaskSchedulerWorkerThreadTest, |
| 257 ::testing::Values(1)); | 269 ::testing::Values(1)); |
| 258 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, | 270 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, |
| 259 TaskSchedulerWorkerThreadTest, | 271 TaskSchedulerWorkerThreadTest, |
| 260 ::testing::Values(2)); | 272 ::testing::Values(2)); |
| 261 | 273 |
| 262 } // namespace | 274 } // namespace |
| 263 } // namespace internal | 275 } // namespace internal |
| 264 } // namespace base | 276 } // namespace base |
| OLD | NEW |