OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "base/task_scheduler/worker_thread.h" |
| 6 |
| 7 #include <stddef.h> |
| 8 |
| 9 #include <vector> |
| 10 |
| 11 #include "base/bind.h" |
| 12 #include "base/bind_helpers.h" |
| 13 #include "base/macros.h" |
| 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/synchronization/condition_variable.h" |
| 16 #include "base/task_scheduler/scheduler_lock.h" |
| 17 #include "base/task_scheduler/sequence.h" |
| 18 #include "base/task_scheduler/task.h" |
| 19 #include "base/task_scheduler/task_tracker.h" |
| 20 #include "testing/gtest/include/gtest/gtest.h" |
| 21 |
| 22 namespace base { |
| 23 namespace internal { |
| 24 namespace { |
| 25 |
| 26 const size_t kNumSequencesPerTest = 150; |
| 27 |
| 28 class TaskSchedulerWorkerThreadTest : public testing::Test { |
| 29 protected: |
| 30 TaskSchedulerWorkerThreadTest() |
| 31 : num_get_work_callback_cv_(lock_.CreateConditionVariable()), |
| 32 run_sequences_cv_(lock_.CreateConditionVariable()) {} |
| 33 |
| 34 void SetUp() override { |
| 35 worker_thread_ = WorkerThread::CreateWorkerThread( |
| 36 ThreadPriority::NORMAL, |
| 37 Bind(&TaskSchedulerWorkerThreadTest::GetWorkCallback, Unretained(this)), |
| 38 Bind(&TaskSchedulerWorkerThreadTest::RanTaskFromSequenceCallback, |
| 39 Unretained(this)), |
| 40 &task_tracker_); |
| 41 ASSERT_TRUE(worker_thread_); |
| 42 } |
| 43 |
| 44 void TearDown() override { worker_thread_->JoinForTesting(); } |
| 45 |
| 46 // Wait until GetWorkCallback() has been called |num_get_work_callback| times. |
| 47 void WaitForNumGetWorkCallback(size_t num_get_work_callback) { |
| 48 AutoSchedulerLock auto_lock(lock_); |
| 49 while (num_get_work_callback_ < num_get_work_callback) |
| 50 num_get_work_callback_cv_->Wait(); |
| 51 } |
| 52 |
| 53 // Wait until there is no more Sequences to create and |
| 54 // RanTaskFromSequenceCallback() has been invoked once for each Sequence |
| 55 // returned by GetWorkCallback(). |
| 56 void WaitForAllSequencesToRun() { |
| 57 AutoSchedulerLock auto_lock(lock_); |
| 58 |
| 59 while (num_sequences_to_create_ > 0 || |
| 60 run_sequences_.size() < created_sequences_.size()) { |
| 61 run_sequences_cv_->Wait(); |
| 62 } |
| 63 |
| 64 // Verify that RanTaskFromSequenceCallback() has been invoked with the |
| 65 // same Sequences that were returned by GetWorkCallback(). |
| 66 EXPECT_EQ(created_sequences_, run_sequences_); |
| 67 |
| 68 // Verify that RunTaskCallback() has been invoked once for each Sequence |
| 69 // returned by GetWorkCallback(). |
| 70 EXPECT_EQ(created_sequences_.size(), num_run_tasks_); |
| 71 } |
| 72 |
| 73 void set_num_sequences_to_create(size_t num_sequences_to_create) { |
| 74 AutoSchedulerLock auto_lock(lock_); |
| 75 EXPECT_EQ(0U, num_sequences_to_create_); |
| 76 num_sequences_to_create_ = num_sequences_to_create; |
| 77 } |
| 78 |
| 79 size_t num_get_work_callback() const { |
| 80 AutoSchedulerLock auto_lock(lock_); |
| 81 return num_get_work_callback_; |
| 82 } |
| 83 |
| 84 scoped_ptr<WorkerThread> worker_thread_; |
| 85 |
| 86 private: |
| 87 // Returns a Sequence that contains 1 Task if |num_sequences_to_create_| is |
| 88 // greater than 0. |
| 89 scoped_refptr<Sequence> GetWorkCallback(const WorkerThread* worker_thread) { |
| 90 EXPECT_EQ(worker_thread_.get(), worker_thread); |
| 91 |
| 92 { |
| 93 AutoSchedulerLock auto_lock(lock_); |
| 94 |
| 95 // Increment the number of times that this callback has been invoked. |
| 96 ++num_get_work_callback_; |
| 97 num_get_work_callback_cv_->Signal(); |
| 98 |
| 99 // Check if a Sequence should be returned. |
| 100 if (num_sequences_to_create_ == 0) |
| 101 return scoped_refptr<Sequence>(); |
| 102 --num_sequences_to_create_; |
| 103 } |
| 104 |
| 105 // Create a Sequence that contains 1 Task. |
| 106 scoped_refptr<Sequence> sequence(new Sequence); |
| 107 task_tracker_.PostTask( |
| 108 Bind(IgnoreResult(&Sequence::PushTask), Unretained(sequence.get())), |
| 109 make_scoped_ptr(new Task( |
| 110 FROM_HERE, Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, |
| 111 Unretained(this)), |
| 112 TaskTraits()))); |
| 113 |
| 114 { |
| 115 // Add the Sequence to the vector of created Sequences. |
| 116 AutoSchedulerLock auto_lock(lock_); |
| 117 created_sequences_.push_back(sequence); |
| 118 } |
| 119 |
| 120 return sequence; |
| 121 } |
| 122 |
| 123 void RanTaskFromSequenceCallback(const WorkerThread* worker_thread, |
| 124 scoped_refptr<Sequence> sequence) { |
| 125 EXPECT_EQ(worker_thread_.get(), worker_thread); |
| 126 |
| 127 AutoSchedulerLock auto_lock(lock_); |
| 128 run_sequences_.push_back(std::move(sequence)); |
| 129 run_sequences_cv_->Signal(); |
| 130 } |
| 131 |
| 132 void RunTaskCallback() { |
| 133 AutoSchedulerLock auto_lock(lock_); |
| 134 ++num_run_tasks_; |
| 135 } |
| 136 |
| 137 TaskTracker task_tracker_; |
| 138 |
| 139 // Synchronizes access to all members below. |
| 140 mutable SchedulerLock lock_; |
| 141 |
| 142 // Number of Sequences that should be created by GetWorkCallback(). When this |
| 143 // is 0, GetWorkCallback() returns nullptr. |
| 144 size_t num_sequences_to_create_ = 0; |
| 145 |
| 146 // Number of times that GetWorkCallback() has been called. |
| 147 size_t num_get_work_callback_ = 0; |
| 148 |
| 149 // Condition variable signaled when |num_get_work_callback_| is incremented. |
| 150 scoped_ptr<ConditionVariable> num_get_work_callback_cv_; |
| 151 |
| 152 // Sequences created by GetWorkCallback(). |
| 153 std::vector<scoped_refptr<Sequence>> created_sequences_; |
| 154 |
| 155 // Sequences passed to RanTaskFromSequenceCallback(). |
| 156 std::vector<scoped_refptr<Sequence>> run_sequences_; |
| 157 |
| 158 // Condition variable signaled when a Sequence is added to |run_sequences_|. |
| 159 scoped_ptr<ConditionVariable> run_sequences_cv_; |
| 160 |
| 161 // Number of times that RunTaskCallback() has been called. |
| 162 size_t num_run_tasks_ = 0; |
| 163 |
| 164 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerThreadTest); |
| 165 }; |
| 166 |
| 167 // Verify that when GetWorkCallback() continuously returns Sequences, all Tasks |
| 168 // in these Sequences run successfully. The WorkerThread is woken up once. |
| 169 TEST_F(TaskSchedulerWorkerThreadTest, ContinousWork) { |
| 170 // Set GetWorkCallback() to return |kNumSequencesPerTest| Sequences before |
| 171 // starting to return nullptr. |
| 172 set_num_sequences_to_create(kNumSequencesPerTest); |
| 173 |
| 174 // Wake up |worker_thread_| and wait until it has run all the Tasks returned |
| 175 // by GetWorkCallback(). |
| 176 worker_thread_->WakeUp(); |
| 177 WaitForAllSequencesToRun(); |
| 178 |
| 179 // Expect |kNumSequencesPerTest| calls to GetWorkCallback() in which it |
| 180 // returned a Sequence and 1 call in which it returned nullptr. |
| 181 const size_t expected_num_get_work_callback = kNumSequencesPerTest + 1; |
| 182 WaitForNumGetWorkCallback(expected_num_get_work_callback); |
| 183 EXPECT_EQ(expected_num_get_work_callback, num_get_work_callback()); |
| 184 } |
| 185 |
| 186 // Verify that when GetWorkCallback() alternates between returning a Sequence |
| 187 // and returning nullptr, all Tasks in the returned Sequences run successfully. |
| 188 // The WorkerThread is woken up once for each Sequence. |
| 189 TEST_F(TaskSchedulerWorkerThreadTest, IntermittentWork) { |
| 190 for (size_t i = 0; i < kNumSequencesPerTest; ++i) { |
| 191 // Set GetWorkCallback() to return 1 Sequence before starting to return |
| 192 // nullptr. |
| 193 set_num_sequences_to_create(1); |
| 194 |
| 195 // Wake up |worker_thread_| and wait until it has run all the Tasks returned |
| 196 // by GetWorkCallback(). |
| 197 worker_thread_->WakeUp(); |
| 198 WaitForAllSequencesToRun(); |
| 199 |
| 200 // Let the WorkerThread go to sleep. |
| 201 PlatformThread::Sleep(TimeDelta::FromMilliseconds(25)); |
| 202 |
| 203 // Expect |i| calls to GetWorkCallback() in which it returned a Sequence and |
| 204 // |i| calls in which it returned nullptr. |
| 205 const size_t expected_num_get_work_callback = 2 * (i + 1); |
| 206 WaitForNumGetWorkCallback(expected_num_get_work_callback); |
| 207 EXPECT_EQ(expected_num_get_work_callback, num_get_work_callback()); |
| 208 } |
| 209 } |
| 210 |
| 211 } // namespace |
| 212 } // namespace internal |
| 213 } // namespace base |
OLD | NEW |