Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: base/task_scheduler/worker_thread_unittest.cc

Issue 1704113002: TaskScheduler [6] SchedulerWorkerThread (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s_4_shutdown
Patch Set: CR robliao #31 Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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) {
danakj 2016/03/31 00:25:14 nit: SetNumSequencesToCreate. this isn't just a si
fdoray 2016/03/31 03:26:31 Done.
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 {
danakj 2016/03/31 00:25:13 nitto, NumGetWorkCallback, locking make this not "
fdoray 2016/03/31 03:26:31 Done.
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_);
danakj 2016/03/31 00:25:13 Am I imagining deadlocks here? WaitForNumGetWorkCa
fdoray 2016/03/31 03:26:31 It is a requirement of ConditionVariable to acquir
fdoray 2016/03/31 13:29:24 In fact, holding the ConditionVariable's lock is o
danakj 2016/03/31 22:33:49 oh.. right I was missing that the CV is tied to th
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>();
danakj 2016/03/31 00:25:13 return nullptr;
fdoray 2016/03/31 03:26:31 Done.
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.
danakj 2016/03/31 00:25:13 ? This looks like a flakey way to avoid races, bu
fdoray 2016/03/31 03:26:31 Removed it. The goal was to give enough time to Wo
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
OLDNEW
« base/task_scheduler/worker_thread.cc ('K') | « base/task_scheduler/worker_thread.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698