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

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: rebase Created 4 years, 9 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 "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_forward.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/synchronization/condition_variable.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/task_scheduler/priority_queue.h"
15 #include "base/task_scheduler/scheduler_lock.h"
16 #include "base/task_scheduler/task_tracker.h"
17 #include "base/task_scheduler/utils.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace base {
21 namespace internal {
22
23 class TaskSchedulerWorkerThreadTest : public testing::Test {
24 protected:
25 TaskSchedulerWorkerThreadTest()
26 : shared_priority_queue_(Bind(&DoNothing)),
27 worker_thread_(WorkerThread::CreateWorkerThread(
robliao 2016/03/09 15:41:12 The worker thread may start and call the idle call
fdoray 2016/03/14 20:46:35 Thanks!
28 ThreadPriority::NORMAL,
29 &shared_priority_queue_,
30 Bind(&TaskSchedulerWorkerThreadTest::ReinsertSequenceCallback,
31 Unretained(this)),
32 Bind(&TaskSchedulerWorkerThreadTest::BecomesIdleCallback,
33 Unretained(this)),
34 &task_tracker_)),
35 run_task_cv_(lock_.CreateConditionVariable()),
36 becomes_idle_callback_cv_(lock_.CreateConditionVariable()),
37 num_becomes_idle_callback_invocations_(0),
38 last_posted_task_index_(0),
39 last_run_task_index_(0),
40 ran_task_that_should_not_run_(false),
41 ran_tasks_in_wrong_order_(true) {}
42
43 Closure GetTaskThatShouldRunClosure() {
44 ++last_posted_task_index_;
45 return Bind(&TaskSchedulerWorkerThreadTest::RunTaskThatShouldRun,
46 Unretained(this), last_posted_task_index_);
47 }
48
49 Closure GetTaskThatShouldNotRunClosure() {
50 return Bind(&TaskSchedulerWorkerThreadTest::RunTaskThatShouldNotRun,
51 Unretained(this));
52 }
53
54 void WaitUntilLastPostedTaskHasRun() {
55 AutoSchedulerLock auto_lock(lock_);
56 while (last_posted_task_index_ != last_run_task_index_)
57 run_task_cv_->Wait();
58 }
59
60 void ExpectLastPostedTaskHasRun() {
61 AutoSchedulerLock auto_lock(lock_);
62 EXPECT_EQ(last_posted_task_index_, last_run_task_index_);
63 }
64
65 void WaitUntilNumBecomesIdleCallbackInvocations(
66 size_t expected_num_becomes_idle_callback_invocations) {
67 AutoSchedulerLock auto_lock(lock_);
68 while (num_becomes_idle_callback_invocations_ !=
69 expected_num_becomes_idle_callback_invocations) {
70 EXPECT_LT(num_becomes_idle_callback_invocations_,
71 expected_num_becomes_idle_callback_invocations);
72 becomes_idle_callback_cv_->Wait();
73 }
74 }
75
76 bool ran_task_that_should_not_run() const {
77 return ran_task_that_should_not_run_;
78 }
79
80 protected:
81 PriorityQueue shared_priority_queue_;
82 TaskTracker task_tracker_;
83 scoped_ptr<WorkerThread> worker_thread_;
84
85 private:
86 void ReinsertSequenceCallback(scoped_refptr<Sequence> sequence,
87 const WorkerThread* worker_thread) {
88 const SequenceSortKey sort_key = sequence->GetSortKey();
89 shared_priority_queue_.BeginTransaction()->Push(make_scoped_ptr(
90 new PriorityQueue::SequenceAndSortKey(std::move(sequence), sort_key)));
91 }
92
93 void BecomesIdleCallback(WorkerThread* worker_thread) {
94 AutoSchedulerLock auto_lock(lock_);
95 ++num_becomes_idle_callback_invocations_;
96 becomes_idle_callback_cv_->Signal();
97 }
98
99 void RunTaskThatShouldRun(size_t index) {
100 AutoSchedulerLock auto_lock(lock_);
101
102 if (index != last_run_task_index_ + 1)
103 ran_tasks_in_wrong_order_ = true;
104
105 last_run_task_index_ = index;
106 run_task_cv_->Signal();
107 }
108
109 void RunTaskThatShouldNotRun() { ran_task_that_should_not_run_ = true; }
110
111 // Lock protecting |run_task_cv_|.
112 SchedulerLock lock_;
113
114 // Condition variable signaled each time a task completes its execution.
115 scoped_ptr<ConditionVariable> run_task_cv_;
116
117 // Condition variable signaled when BecomesIdleCallback() is invoked.
118 scoped_ptr<ConditionVariable> becomes_idle_callback_cv_;
119
120 // Number of times that BecomesIdleCallback() has been called.
121 size_t num_becomes_idle_callback_invocations_;
122
123 // Index of the last posted task.
124 size_t last_posted_task_index_;
125
126 // Index of the last run task.
127 size_t last_run_task_index_;
128
129 // True if a task that shouldn't run has run.
130 bool ran_task_that_should_not_run_;
131
132 // True if tasks were run in the wrong order.
133 bool ran_tasks_in_wrong_order_;
134
135 };
136
137 TEST_F(TaskSchedulerWorkerThreadTest, PostOneSingleThreadedTask) {
138 ASSERT_NE(nullptr, worker_thread_.get());
139 WaitUntilNumBecomesIdleCallbackInvocations(1);
140
141 worker_thread_->CreateTaskRunnerWithTraits(TaskTraits())
142 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure());
143
144 WaitUntilNumBecomesIdleCallbackInvocations(2);
145 ExpectLastPostedTaskHasRun();
146 worker_thread_->JoinForTesting();
147 }
148
149 TEST_F(TaskSchedulerWorkerThreadTest,
150 PostMultipleSingleThreadedTasksNoWaitBetweenPosts) {
151 ASSERT_NE(nullptr, worker_thread_.get());
152 WaitUntilNumBecomesIdleCallbackInvocations(1);
153
154 auto task_runner = worker_thread_->CreateTaskRunnerWithTraits(TaskTraits());
155
156 for (size_t i = 0; i < 100; ++i)
157 task_runner->PostTask(FROM_HERE, GetTaskThatShouldRunClosure());
158
159 WaitUntilLastPostedTaskHasRun();
160 worker_thread_->JoinForTesting();
161 }
162
163 TEST_F(TaskSchedulerWorkerThreadTest,
164 PostMultipleSingleThreadedTasksWaitBetweenPosts) {
165 ASSERT_NE(nullptr, worker_thread_.get());
166 WaitUntilNumBecomesIdleCallbackInvocations(1);
167
168 auto task_runner = worker_thread_->CreateTaskRunnerWithTraits(TaskTraits());
169
170 for (size_t i = 0; i < 100; ++i) {
171 task_runner->PostTask(FROM_HERE, GetTaskThatShouldRunClosure());
172 WaitUntilLastPostedTaskHasRun();
173 WaitUntilNumBecomesIdleCallbackInvocations(2 + i);
174 }
175
176 worker_thread_->JoinForTesting();
177 }
178
179 TEST_F(TaskSchedulerWorkerThreadTest,
180 PostMultipleTasksTwoSingleThreadedTaskRunners) {
181 ASSERT_NE(nullptr, worker_thread_.get());
182 WaitUntilNumBecomesIdleCallbackInvocations(1);
183
184 auto task_runner_a = worker_thread_->CreateTaskRunnerWithTraits(TaskTraits());
185 auto task_runner_b = worker_thread_->CreateTaskRunnerWithTraits(TaskTraits());
186
187 for (size_t i = 0; i < 100; ++i) {
188 task_runner_a->PostTask(FROM_HERE, GetTaskThatShouldRunClosure());
189 task_runner_b->PostTask(FROM_HERE, GetTaskThatShouldRunClosure());
190 }
191
192 WaitUntilLastPostedTaskHasRun();
193 worker_thread_->JoinForTesting();
194 }
195
196 TEST_F(TaskSchedulerWorkerThreadTest, PostOneTaskInSharedPriorityQueue) {
197 ASSERT_NE(nullptr, worker_thread_.get());
198 WaitUntilNumBecomesIdleCallbackInvocations(1);
199
200 PostTaskHelper(make_scoped_ptr(new Task(
201 FROM_HERE, GetTaskThatShouldRunClosure(), TaskTraits())),
202 new Sequence, &shared_priority_queue_, &task_tracker_);
203 EXPECT_TRUE(worker_thread_->WakeUp());
204
205 WaitUntilNumBecomesIdleCallbackInvocations(2);
206 ExpectLastPostedTaskHasRun();
207 worker_thread_->JoinForTesting();
208 }
209
210 TEST_F(TaskSchedulerWorkerThreadTest, PostSharedAndSingleThreadedTasks) {
211 ASSERT_NE(nullptr, worker_thread_.get());
212 WaitUntilNumBecomesIdleCallbackInvocations(1);
213
214 // Post a task in the shared priority queue.
215 PostTaskHelper(make_scoped_ptr(new Task(
216 FROM_HERE, GetTaskThatShouldRunClosure(), TaskTraits())),
217 new Sequence, &shared_priority_queue_, &task_tracker_);
218
219 // Post a task in the single-threaded priority queue. The TaskRunner will wake
220 // up the WorkerThread.
221 worker_thread_->CreateTaskRunnerWithTraits(TaskTraits())
222 ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure());
223
224 WaitUntilNumBecomesIdleCallbackInvocations(2);
225 ExpectLastPostedTaskHasRun();
226 worker_thread_->JoinForTesting();
227 }
228
229 TEST_F(TaskSchedulerWorkerThreadTest, WakeUpIdleThread) {
230 ASSERT_NE(nullptr, worker_thread_.get());
231 WaitUntilNumBecomesIdleCallbackInvocations(1);
232
233 EXPECT_TRUE(worker_thread_->WakeUp());
234 WaitUntilNumBecomesIdleCallbackInvocations(2);
235
236 worker_thread_->JoinForTesting();
237 }
238
239 TEST_F(TaskSchedulerWorkerThreadTest, WakeUpBusyThread) {
240 ASSERT_NE(nullptr, worker_thread_.get());
241 WaitUntilNumBecomesIdleCallbackInvocations(1);
242
243 // Post a task.
244 WaitableEvent event(false, false);
245 worker_thread_->CreateTaskRunnerWithTraits(TaskTraits())
246 ->PostTask(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)));
247
248 // Because the thread is busy, WakeUp() should return false.
249 EXPECT_FALSE(worker_thread_->WakeUp());
250
251 event.Signal();
252 WaitUntilNumBecomesIdleCallbackInvocations(2);
253 worker_thread_->JoinForTesting();
254 }
255
256 } // namespace internal
257 } // 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