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

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

Issue 2698843006: Introduce SchedulerSingleThreadTaskRunnerManager (Closed)
Patch Set: Merge in https://codereview.chromium.org/2726073002/ Created 3 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 2017 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/scheduler_single_thread_task_runner_manager.h"
6
7 #include "base/bind.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/synchronization/lock.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/task_scheduler/delayed_task_manager.h"
12 #include "base/task_scheduler/post_task.h"
13 #include "base/task_scheduler/scheduler_worker_pool_params.h"
14 #include "base/task_scheduler/task_tracker.h"
15 #include "base/task_scheduler/task_traits.h"
16 #include "base/test/test_timeouts.h"
17 #include "base/threading/simple_thread.h"
18 #include "base/threading/thread.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace base {
22 namespace internal {
23
24 namespace {
25
26 enum WorkerPoolType : size_t {
27 BACKGROUND_WORKER_POOL = 0,
28 FOREGROUND_WORKER_POOL,
29 };
30
31 static size_t GetThreadPoolIndexForTraits(const TaskTraits& traits) {
32 return traits.priority() == TaskPriority::BACKGROUND ? BACKGROUND_WORKER_POOL
33 : FOREGROUND_WORKER_POOL;
34 }
35
36 std::vector<SchedulerWorkerPoolParams> GetParamsVector() {
37 using StandbyThreadPolicy = SchedulerWorkerPoolParams::StandbyThreadPolicy;
38
39 std::vector<SchedulerWorkerPoolParams> params_vector;
40
41 DCHECK_EQ(BACKGROUND_WORKER_POOL, params_vector.size());
42 params_vector.emplace_back("Background", ThreadPriority::BACKGROUND,
43 StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max());
44
45 DCHECK_EQ(FOREGROUND_WORKER_POOL, params_vector.size());
46 params_vector.emplace_back("Foreground", ThreadPriority::NORMAL,
47 StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max());
48
49 return params_vector;
50 }
51
52 class TaskSchedulerSingleThreadTaskRunnerManagerTest : public testing::Test {
53 public:
54 TaskSchedulerSingleThreadTaskRunnerManagerTest()
55 : service_thread_("TaskSchedulerServiceThread") {}
56
57 void SetUp() override {
58 service_thread_.Start();
59
60 delayed_task_manager_ =
61 MakeUnique<DelayedTaskManager>(service_thread_.task_runner());
62 single_thread_task_runner_manager_ =
63 MakeUnique<SchedulerSingleThreadTaskRunnerManager>(
64 GetParamsVector(), Bind(&GetThreadPoolIndexForTraits),
65 &task_tracker_, delayed_task_manager_.get());
66 }
67
68 void TearDown() override {
69 TearDownSingleThreadTaskRunnerManager();
70 delayed_task_manager_.reset();
71 service_thread_.Stop();
72 }
73
74 protected:
75 virtual void TearDownSingleThreadTaskRunnerManager() {
76 single_thread_task_runner_manager_->JoinForTesting();
77 single_thread_task_runner_manager_.reset();
78 }
79
80 std::unique_ptr<SchedulerSingleThreadTaskRunnerManager>
81 single_thread_task_runner_manager_;
82 TaskTracker task_tracker_;
83
84 private:
85 Thread service_thread_;
86 std::unique_ptr<DelayedTaskManager> delayed_task_manager_;
87
88 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTest);
89 };
90
91 void CaptureThreadRef(PlatformThreadRef* thread_ref) {
92 ASSERT_TRUE(thread_ref);
93 *thread_ref = PlatformThread::CurrentRef();
94 }
95
96 void CaptureThreadPriority(ThreadPriority* thread_priority) {
97 ASSERT_TRUE(thread_priority);
98 *thread_priority = PlatformThread::GetCurrentThreadPriority();
99 }
100
101 void ShouldNotRun() {
102 ADD_FAILURE() << "Ran a task that shouldn't run.";
103 }
104
105 } // namespace
106
107 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, DifferentThreadsUsed) {
108 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
109 single_thread_task_runner_manager_
110 ->CreateSingleThreadTaskRunnerWithTraits(
111 TaskTraits().WithShutdownBehavior(
112 TaskShutdownBehavior::BLOCK_SHUTDOWN));
113 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
114 single_thread_task_runner_manager_
115 ->CreateSingleThreadTaskRunnerWithTraits(
116 TaskTraits().WithShutdownBehavior(
117 TaskShutdownBehavior::BLOCK_SHUTDOWN));
118
119 PlatformThreadRef thread_ref_1;
120 task_runner_1->PostTask(FROM_HERE, Bind(&CaptureThreadRef, &thread_ref_1));
121 PlatformThreadRef thread_ref_2;
122 task_runner_2->PostTask(FROM_HERE, Bind(&CaptureThreadRef, &thread_ref_2));
123
124 task_tracker_.Shutdown();
125
126 ASSERT_FALSE(thread_ref_1.is_null());
127 ASSERT_FALSE(thread_ref_2.is_null());
128 EXPECT_NE(thread_ref_1, thread_ref_2);
129 }
130
131 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PrioritySetCorrectly) {
132 // Why are events used here instead of the task tracker?
133 // Shutting down can cause priorities to get raised. This means we have to use
134 // events to determine when a task is run.
135 scoped_refptr<SingleThreadTaskRunner> task_runner_background =
136 single_thread_task_runner_manager_
137 ->CreateSingleThreadTaskRunnerWithTraits(
138 TaskTraits().WithPriority(TaskPriority::BACKGROUND));
139 scoped_refptr<SingleThreadTaskRunner> task_runner_user_visible =
140 single_thread_task_runner_manager_
141 ->CreateSingleThreadTaskRunnerWithTraits(
142 TaskTraits().WithPriority(TaskPriority::USER_VISIBLE));
143 scoped_refptr<SingleThreadTaskRunner> task_runner_user_blocking =
144 single_thread_task_runner_manager_
145 ->CreateSingleThreadTaskRunnerWithTraits(
146 TaskTraits()
147 .WithPriority(TaskPriority::USER_BLOCKING)
148 .WithShutdownBehavior(TaskShutdownBehavior::BLOCK_SHUTDOWN));
149
150 ThreadPriority thread_priority_background;
151 task_runner_background->PostTask(
152 FROM_HERE, Bind(&CaptureThreadPriority, &thread_priority_background));
153 WaitableEvent waitable_event_background(
154 WaitableEvent::ResetPolicy::MANUAL,
155 WaitableEvent::InitialState::NOT_SIGNALED);
156 task_runner_background->PostTask(
157 FROM_HERE,
158 Bind(&WaitableEvent::Signal, Unretained(&waitable_event_background)));
159
160 ThreadPriority thread_priority_user_visible;
161 task_runner_user_visible->PostTask(
162 FROM_HERE, Bind(&CaptureThreadPriority, &thread_priority_user_visible));
163 WaitableEvent waitable_event_user_visible(
164 WaitableEvent::ResetPolicy::MANUAL,
165 WaitableEvent::InitialState::NOT_SIGNALED);
166 task_runner_user_visible->PostTask(
167 FROM_HERE,
168 Bind(&WaitableEvent::Signal, Unretained(&waitable_event_user_visible)));
169
170 ThreadPriority thread_priority_user_blocking;
171 task_runner_user_blocking->PostTask(
172 FROM_HERE, Bind(&CaptureThreadPriority, &thread_priority_user_blocking));
173 WaitableEvent waitable_event_user_blocking(
174 WaitableEvent::ResetPolicy::MANUAL,
175 WaitableEvent::InitialState::NOT_SIGNALED);
176 task_runner_user_blocking->PostTask(
177 FROM_HERE,
178 Bind(&WaitableEvent::Signal, Unretained(&waitable_event_user_blocking)));
179
180 waitable_event_background.Wait();
181 waitable_event_user_visible.Wait();
182 waitable_event_user_blocking.Wait();
183
184 if (Lock::HandlesMultipleThreadPriorities())
185 EXPECT_EQ(ThreadPriority::BACKGROUND, thread_priority_background);
186 else
187 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_background);
188 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_user_visible);
189 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_user_blocking);
190 }
191
192 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PostTaskAfterShutdown) {
193 auto task_runner = single_thread_task_runner_manager_
194 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits());
195 task_tracker_.Shutdown();
196 EXPECT_FALSE(task_runner->PostTask(FROM_HERE, Bind(&ShouldNotRun)));
197 }
198
199 // Verify that a Task runs shortly after its delay expires.
200 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, PostDelayedTask) {
201 TimeTicks start_time = TimeTicks::Now();
202
203 // Post a task with a short delay.
204 WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL,
205 WaitableEvent::InitialState::NOT_SIGNALED);
206 auto task_runner = single_thread_task_runner_manager_
207 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits());
208 EXPECT_TRUE(task_runner->PostDelayedTask(
209 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_ran)),
210 TestTimeouts::tiny_timeout()));
211
212 // Wait until the task runs.
213 task_ran.Wait();
214
215 // Expect the task to run after its delay expires, but not more than 250 ms
216 // after that.
217 const TimeDelta actual_delay = TimeTicks::Now() - start_time;
218 EXPECT_GE(actual_delay, TestTimeouts::tiny_timeout());
219 EXPECT_LT(actual_delay,
220 TimeDelta::FromMilliseconds(250) + TestTimeouts::tiny_timeout());
221 }
222
223 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest,
224 RunsTasksOnCurrentThread) {
225 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
226 single_thread_task_runner_manager_
227 ->CreateSingleThreadTaskRunnerWithTraits(
228 TaskTraits().WithShutdownBehavior(
229 TaskShutdownBehavior::BLOCK_SHUTDOWN));
230 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
231 single_thread_task_runner_manager_
232 ->CreateSingleThreadTaskRunnerWithTraits(
233 TaskTraits().WithShutdownBehavior(
234 TaskShutdownBehavior::BLOCK_SHUTDOWN));
235
236 EXPECT_FALSE(task_runner_1->RunsTasksOnCurrentThread());
237 EXPECT_FALSE(task_runner_2->RunsTasksOnCurrentThread());
238
239 task_runner_1->PostTask(
240 FROM_HERE, Bind(
241 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1,
242 scoped_refptr<SingleThreadTaskRunner> task_runner_2) {
243 EXPECT_TRUE(task_runner_1->RunsTasksOnCurrentThread());
244 EXPECT_FALSE(task_runner_2->RunsTasksOnCurrentThread());
245 },
246 task_runner_1, task_runner_2));
247
248 task_runner_2->PostTask(
249 FROM_HERE, Bind(
250 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1,
251 scoped_refptr<SingleThreadTaskRunner> task_runner_2) {
252 EXPECT_FALSE(task_runner_1->RunsTasksOnCurrentThread());
253 EXPECT_TRUE(task_runner_2->RunsTasksOnCurrentThread());
254 },
255 task_runner_1, task_runner_2));
256
257 task_tracker_.Shutdown();
258 }
259
260 namespace {
261
262 class CallJoinFromDifferentThread : public SimpleThread {
263 public:
264 CallJoinFromDifferentThread(
265 SchedulerSingleThreadTaskRunnerManager* manager_to_join)
266 : SimpleThread("SchedulerSingleThreadTaskRunnerManagerJoinThread"),
267 manager_to_join_(manager_to_join),
268 run_started_event_(WaitableEvent::ResetPolicy::MANUAL,
269 WaitableEvent::InitialState::NOT_SIGNALED) {}
270
271 ~CallJoinFromDifferentThread() override = default;
272
273 void Run() override {
274 run_started_event_.Signal();
275 manager_to_join_->JoinForTesting();
276 }
277
278 void WaitForRunToStart() { run_started_event_.Wait(); }
279
280 private:
281 SchedulerSingleThreadTaskRunnerManager* const manager_to_join_;
282 WaitableEvent run_started_event_;
283 DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread);
284 };
285
286 class TaskSchedulerSingleThreadTaskRunnerManagerJoinTest
287 : public TaskSchedulerSingleThreadTaskRunnerManagerTest {
288 public:
289 TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() = default;
290 ~TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() override = default;
291
292 protected:
293 void TearDownSingleThreadTaskRunnerManager() override {
294 // The tests themselves are responsible for calling JoinForTesting().
295 single_thread_task_runner_manager_.reset();
296 }
297
298 private:
299 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest);
300 };
301
302 } // namespace
303
304 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) {
305 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL,
306 WaitableEvent::InitialState::NOT_SIGNALED);
307 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL,
308 WaitableEvent::InitialState::NOT_SIGNALED);
309
310 {
311 auto task_runner = single_thread_task_runner_manager_
312 ->CreateSingleThreadTaskRunnerWithTraits(
313 TaskTraits().WithBaseSyncPrimitives());
314 EXPECT_TRUE(task_runner->PostTask(
315 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running))));
316 EXPECT_TRUE(task_runner->PostTask(
317 FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking))));
318 }
319
320 task_running.Wait();
321 CallJoinFromDifferentThread join_from_different_thread(
322 single_thread_task_runner_manager_.get());
323 join_from_different_thread.Start();
324 join_from_different_thread.WaitForRunToStart();
325 task_blocking.Signal();
326 join_from_different_thread.Join();
327 }
328
329 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest,
330 ConcurrentJoinExtraSkippedTask) {
331 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL,
332 WaitableEvent::InitialState::NOT_SIGNALED);
333 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL,
334 WaitableEvent::InitialState::NOT_SIGNALED);
335
336 {
337 auto task_runner = single_thread_task_runner_manager_
338 ->CreateSingleThreadTaskRunnerWithTraits(
339 TaskTraits().WithBaseSyncPrimitives());
340 EXPECT_TRUE(task_runner->PostTask(
341 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running))));
342 EXPECT_TRUE(task_runner->PostTask(
343 FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking))));
344 EXPECT_TRUE(task_runner->PostTask(FROM_HERE, Bind(&DoNothing)));
345 }
346
347 task_running.Wait();
348 CallJoinFromDifferentThread join_from_different_thread(
349 single_thread_task_runner_manager_.get());
350 join_from_different_thread.Start();
351 join_from_different_thread.WaitForRunToStart();
352 task_blocking.Signal();
353 join_from_different_thread.Join();
354 }
355
356 } // namespace internal
357 } // namespace base
OLDNEW
« no previous file with comments | « base/task_scheduler/scheduler_single_thread_task_runner_manager.cc ('k') | base/task_scheduler/scheduler_worker.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698