blob: add274e1b7330b655a2ce296dc17db911ee39de9 [file] [log] [blame]
robliao19e3ad72017-03-11 05:21:29 +09001// 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"
Peter Kasting88430fa2018-02-13 15:22:40 +09008#include "base/bind_helpers.h"
robliao19e3ad72017-03-11 05:21:29 +09009#include "base/memory/ptr_util.h"
fdorayd952d8e2017-04-19 09:37:26 +090010#include "base/synchronization/atomic_flag.h"
robliao19e3ad72017-03-11 05:21:29 +090011#include "base/synchronization/lock.h"
12#include "base/synchronization/waitable_event.h"
13#include "base/task_scheduler/delayed_task_manager.h"
14#include "base/task_scheduler/post_task.h"
15#include "base/task_scheduler/scheduler_worker_pool_params.h"
16#include "base/task_scheduler/task_tracker.h"
17#include "base/task_scheduler/task_traits.h"
robliao7d2bb1e2017-05-26 06:33:43 +090018#include "base/test/gtest_util.h"
robliao19e3ad72017-03-11 05:21:29 +090019#include "base/test/test_timeouts.h"
fdorayd952d8e2017-04-19 09:37:26 +090020#include "base/threading/platform_thread.h"
robliao19e3ad72017-03-11 05:21:29 +090021#include "base/threading/simple_thread.h"
22#include "base/threading/thread.h"
23#include "testing/gtest/include/gtest/gtest.h"
24
robliaof81c0002017-03-23 07:30:15 +090025#if defined(OS_WIN)
26#include <windows.h>
robliaof81c0002017-03-23 07:30:15 +090027
Robert Liaob01a9972017-07-07 09:54:14 +090028#include "base/win/com_init_util.h"
robliaof81c0002017-03-23 07:30:15 +090029#include "base/win/current_module.h"
30#endif // defined(OS_WIN)
31
robliao19e3ad72017-03-11 05:21:29 +090032namespace base {
33namespace internal {
34
35namespace {
36
robliao19e3ad72017-03-11 05:21:29 +090037class TaskSchedulerSingleThreadTaskRunnerManagerTest : public testing::Test {
38 public:
39 TaskSchedulerSingleThreadTaskRunnerManagerTest()
40 : service_thread_("TaskSchedulerServiceThread") {}
41
42 void SetUp() override {
43 service_thread_.Start();
fdoray4a475d62017-04-20 22:13:11 +090044 delayed_task_manager_.Start(service_thread_.task_runner());
robliao19e3ad72017-03-11 05:21:29 +090045 single_thread_task_runner_manager_ =
Jeremy Romancd0c4672017-08-17 08:27:24 +090046 std::make_unique<SchedulerSingleThreadTaskRunnerManager>(
fdoray4a475d62017-04-20 22:13:11 +090047 &task_tracker_, &delayed_task_manager_);
fdorayd952d8e2017-04-19 09:37:26 +090048 StartSingleThreadTaskRunnerManagerFromSetUp();
robliao19e3ad72017-03-11 05:21:29 +090049 }
50
51 void TearDown() override {
Gabriel Charettec37bf442017-09-21 11:26:13 +090052 if (single_thread_task_runner_manager_)
53 TearDownSingleThreadTaskRunnerManager();
robliao19e3ad72017-03-11 05:21:29 +090054 service_thread_.Stop();
55 }
56
57 protected:
fdorayd952d8e2017-04-19 09:37:26 +090058 virtual void StartSingleThreadTaskRunnerManagerFromSetUp() {
59 single_thread_task_runner_manager_->Start();
60 }
61
robliao19e3ad72017-03-11 05:21:29 +090062 virtual void TearDownSingleThreadTaskRunnerManager() {
63 single_thread_task_runner_manager_->JoinForTesting();
64 single_thread_task_runner_manager_.reset();
65 }
66
67 std::unique_ptr<SchedulerSingleThreadTaskRunnerManager>
68 single_thread_task_runner_manager_;
Gabriel Charette19075392018-01-19 20:00:53 +090069 TaskTracker task_tracker_ = {"Test"};
robliao19e3ad72017-03-11 05:21:29 +090070
71 private:
72 Thread service_thread_;
fdoray4a475d62017-04-20 22:13:11 +090073 DelayedTaskManager delayed_task_manager_;
robliao19e3ad72017-03-11 05:21:29 +090074
75 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTest);
76};
77
78void CaptureThreadRef(PlatformThreadRef* thread_ref) {
79 ASSERT_TRUE(thread_ref);
80 *thread_ref = PlatformThread::CurrentRef();
81}
82
83void CaptureThreadPriority(ThreadPriority* thread_priority) {
84 ASSERT_TRUE(thread_priority);
85 *thread_priority = PlatformThread::GetCurrentThreadPriority();
86}
87
robliao7d2bb1e2017-05-26 06:33:43 +090088void CaptureThreadName(std::string* thread_name) {
89 *thread_name = PlatformThread::GetName();
90}
91
robliao19e3ad72017-03-11 05:21:29 +090092void ShouldNotRun() {
93 ADD_FAILURE() << "Ran a task that shouldn't run.";
94}
95
96} // namespace
97
98TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, DifferentThreadsUsed) {
99 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
100 single_thread_task_runner_manager_
101 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900102 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900103 SingleThreadTaskRunnerThreadMode::DEDICATED);
robliao19e3ad72017-03-11 05:21:29 +0900104 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
105 single_thread_task_runner_manager_
106 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900107 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900108 SingleThreadTaskRunnerThreadMode::DEDICATED);
robliao19e3ad72017-03-11 05:21:29 +0900109
110 PlatformThreadRef thread_ref_1;
tzik6bdbeb22017-04-12 00:00:44 +0900111 task_runner_1->PostTask(FROM_HERE,
112 BindOnce(&CaptureThreadRef, &thread_ref_1));
robliao19e3ad72017-03-11 05:21:29 +0900113 PlatformThreadRef thread_ref_2;
tzik6bdbeb22017-04-12 00:00:44 +0900114 task_runner_2->PostTask(FROM_HERE,
115 BindOnce(&CaptureThreadRef, &thread_ref_2));
robliao19e3ad72017-03-11 05:21:29 +0900116
117 task_tracker_.Shutdown();
118
119 ASSERT_FALSE(thread_ref_1.is_null());
120 ASSERT_FALSE(thread_ref_2.is_null());
121 EXPECT_NE(thread_ref_1, thread_ref_2);
122}
123
robliao7d2bb1e2017-05-26 06:33:43 +0900124TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, SameThreadUsed) {
125 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
126 single_thread_task_runner_manager_
127 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900128 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900129 SingleThreadTaskRunnerThreadMode::SHARED);
130 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
131 single_thread_task_runner_manager_
132 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900133 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900134 SingleThreadTaskRunnerThreadMode::SHARED);
135
136 PlatformThreadRef thread_ref_1;
137 task_runner_1->PostTask(FROM_HERE,
138 BindOnce(&CaptureThreadRef, &thread_ref_1));
139 PlatformThreadRef thread_ref_2;
140 task_runner_2->PostTask(FROM_HERE,
141 BindOnce(&CaptureThreadRef, &thread_ref_2));
142
143 task_tracker_.Shutdown();
144
145 ASSERT_FALSE(thread_ref_1.is_null());
146 ASSERT_FALSE(thread_ref_2.is_null());
147 EXPECT_EQ(thread_ref_1, thread_ref_2);
148}
149
150TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest,
Yeol0d4f3eb2017-07-26 02:09:10 +0900151 RunsTasksInCurrentSequence) {
robliao7d2bb1e2017-05-26 06:33:43 +0900152 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
153 single_thread_task_runner_manager_
154 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900155 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900156 SingleThreadTaskRunnerThreadMode::DEDICATED);
157 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
158 single_thread_task_runner_manager_
159 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900160 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900161 SingleThreadTaskRunnerThreadMode::DEDICATED);
162
Yeol0d4f3eb2017-07-26 02:09:10 +0900163 EXPECT_FALSE(task_runner_1->RunsTasksInCurrentSequence());
164 EXPECT_FALSE(task_runner_2->RunsTasksInCurrentSequence());
robliao7d2bb1e2017-05-26 06:33:43 +0900165
166 task_runner_1->PostTask(
Yeol0d4f3eb2017-07-26 02:09:10 +0900167 FROM_HERE,
168 BindOnce(
169 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1,
170 scoped_refptr<SingleThreadTaskRunner> task_runner_2) {
171 EXPECT_TRUE(task_runner_1->RunsTasksInCurrentSequence());
172 EXPECT_FALSE(task_runner_2->RunsTasksInCurrentSequence());
173 },
174 task_runner_1, task_runner_2));
robliao7d2bb1e2017-05-26 06:33:43 +0900175
176 task_runner_2->PostTask(
Yeol0d4f3eb2017-07-26 02:09:10 +0900177 FROM_HERE,
178 BindOnce(
179 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1,
180 scoped_refptr<SingleThreadTaskRunner> task_runner_2) {
181 EXPECT_FALSE(task_runner_1->RunsTasksInCurrentSequence());
182 EXPECT_TRUE(task_runner_2->RunsTasksInCurrentSequence());
183 },
184 task_runner_1, task_runner_2));
robliao7d2bb1e2017-05-26 06:33:43 +0900185
186 task_tracker_.Shutdown();
187}
188
189TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest,
190 SharedWithBaseSyncPrimitivesDCHECKs) {
191 EXPECT_DCHECK_DEATH({
192 single_thread_task_runner_manager_->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900193 {WithBaseSyncPrimitives()}, SingleThreadTaskRunnerThreadMode::SHARED);
robliao7d2bb1e2017-05-26 06:33:43 +0900194 });
195}
196
197namespace {
198
199class TaskSchedulerSingleThreadTaskRunnerManagerCommonTest
200 : public TaskSchedulerSingleThreadTaskRunnerManagerTest,
201 public ::testing::WithParamInterface<SingleThreadTaskRunnerThreadMode> {
202 public:
203 TaskSchedulerSingleThreadTaskRunnerManagerCommonTest() = default;
204
205 private:
206 DISALLOW_COPY_AND_ASSIGN(
207 TaskSchedulerSingleThreadTaskRunnerManagerCommonTest);
208};
209
210} // namespace
211
212TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest,
213 PrioritySetCorrectly) {
robliao19e3ad72017-03-11 05:21:29 +0900214 // Why are events used here instead of the task tracker?
215 // Shutting down can cause priorities to get raised. This means we have to use
216 // events to determine when a task is run.
217 scoped_refptr<SingleThreadTaskRunner> task_runner_background =
218 single_thread_task_runner_manager_
Gabriel Charettee1640632018-01-19 01:56:31 +0900219 ->CreateSingleThreadTaskRunnerWithTraits({TaskPriority::BACKGROUND},
220 GetParam());
fdoray066b38f2017-04-19 22:42:24 +0900221 scoped_refptr<SingleThreadTaskRunner> task_runner_normal =
robliao19e3ad72017-03-11 05:21:29 +0900222 single_thread_task_runner_manager_
Gabriel Charettee1640632018-01-19 01:56:31 +0900223 ->CreateSingleThreadTaskRunnerWithTraits({TaskPriority::USER_VISIBLE},
224 GetParam());
robliao19e3ad72017-03-11 05:21:29 +0900225
226 ThreadPriority thread_priority_background;
227 task_runner_background->PostTask(
tzik6bdbeb22017-04-12 00:00:44 +0900228 FROM_HERE, BindOnce(&CaptureThreadPriority, &thread_priority_background));
robliao19e3ad72017-03-11 05:21:29 +0900229 WaitableEvent waitable_event_background(
230 WaitableEvent::ResetPolicy::MANUAL,
231 WaitableEvent::InitialState::NOT_SIGNALED);
232 task_runner_background->PostTask(
233 FROM_HERE,
tzik6bdbeb22017-04-12 00:00:44 +0900234 BindOnce(&WaitableEvent::Signal, Unretained(&waitable_event_background)));
robliao19e3ad72017-03-11 05:21:29 +0900235
fdoray066b38f2017-04-19 22:42:24 +0900236 ThreadPriority thread_priority_normal;
237 task_runner_normal->PostTask(
238 FROM_HERE, BindOnce(&CaptureThreadPriority, &thread_priority_normal));
239 WaitableEvent waitable_event_normal(
robliao19e3ad72017-03-11 05:21:29 +0900240 WaitableEvent::ResetPolicy::MANUAL,
241 WaitableEvent::InitialState::NOT_SIGNALED);
fdoray066b38f2017-04-19 22:42:24 +0900242 task_runner_normal->PostTask(
tzik6bdbeb22017-04-12 00:00:44 +0900243 FROM_HERE,
fdoray066b38f2017-04-19 22:42:24 +0900244 BindOnce(&WaitableEvent::Signal, Unretained(&waitable_event_normal)));
robliao19e3ad72017-03-11 05:21:29 +0900245
246 waitable_event_background.Wait();
fdoray066b38f2017-04-19 22:42:24 +0900247 waitable_event_normal.Wait();
robliao19e3ad72017-03-11 05:21:29 +0900248
Ken MacKay9948fde2018-01-04 08:14:15 +0900249 if (Lock::HandlesMultipleThreadPriorities() &&
250 PlatformThread::CanIncreaseCurrentThreadPriority()) {
robliao19e3ad72017-03-11 05:21:29 +0900251 EXPECT_EQ(ThreadPriority::BACKGROUND, thread_priority_background);
Ken MacKay9948fde2018-01-04 08:14:15 +0900252 } else {
robliao19e3ad72017-03-11 05:21:29 +0900253 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_background);
Ken MacKay9948fde2018-01-04 08:14:15 +0900254 }
fdoray066b38f2017-04-19 22:42:24 +0900255 EXPECT_EQ(ThreadPriority::NORMAL, thread_priority_normal);
robliao19e3ad72017-03-11 05:21:29 +0900256}
257
robliao7d2bb1e2017-05-26 06:33:43 +0900258TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, ThreadNamesSet) {
259 constexpr TaskTraits foo_traits = {TaskPriority::BACKGROUND,
260 TaskShutdownBehavior::BLOCK_SHUTDOWN};
261 scoped_refptr<SingleThreadTaskRunner> foo_task_runner =
262 single_thread_task_runner_manager_
Gabriel Charettee1640632018-01-19 01:56:31 +0900263 ->CreateSingleThreadTaskRunnerWithTraits(foo_traits, GetParam());
robliao7d2bb1e2017-05-26 06:33:43 +0900264 std::string foo_captured_name;
265 foo_task_runner->PostTask(FROM_HERE,
266 BindOnce(&CaptureThreadName, &foo_captured_name));
267
268 constexpr TaskTraits user_blocking_traits = {
269 TaskPriority::USER_BLOCKING, MayBlock(),
270 TaskShutdownBehavior::BLOCK_SHUTDOWN};
271 scoped_refptr<SingleThreadTaskRunner> user_blocking_task_runner =
272 single_thread_task_runner_manager_
Gabriel Charettee1640632018-01-19 01:56:31 +0900273 ->CreateSingleThreadTaskRunnerWithTraits(user_blocking_traits,
robliao7d2bb1e2017-05-26 06:33:43 +0900274 GetParam());
275
276 std::string user_blocking_captured_name;
277 user_blocking_task_runner->PostTask(
278 FROM_HERE, BindOnce(&CaptureThreadName, &user_blocking_captured_name));
279
280 task_tracker_.Shutdown();
281
robliao7d2bb1e2017-05-26 06:33:43 +0900282 EXPECT_NE(std::string::npos,
283 foo_captured_name.find(
284 kEnvironmentParams[GetEnvironmentIndexForTraits(foo_traits)]
285 .name_suffix));
286 EXPECT_NE(
287 std::string::npos,
288 user_blocking_captured_name.find(
289 kEnvironmentParams[GetEnvironmentIndexForTraits(user_blocking_traits)]
290 .name_suffix));
291
292 if (GetParam() == SingleThreadTaskRunnerThreadMode::DEDICATED) {
293 EXPECT_EQ(std::string::npos, foo_captured_name.find("Shared"));
294 EXPECT_EQ(std::string::npos, user_blocking_captured_name.find("Shared"));
295 } else {
296 EXPECT_NE(std::string::npos, foo_captured_name.find("Shared"));
297 EXPECT_NE(std::string::npos, user_blocking_captured_name.find("Shared"));
298 }
299}
300
301TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest,
302 PostTaskAfterShutdown) {
Gabriel Charettee1640632018-01-19 01:56:31 +0900303 auto task_runner =
304 single_thread_task_runner_manager_
305 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits(), GetParam());
robliao19e3ad72017-03-11 05:21:29 +0900306 task_tracker_.Shutdown();
tzik6bdbeb22017-04-12 00:00:44 +0900307 EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun)));
robliao19e3ad72017-03-11 05:21:29 +0900308}
309
310// Verify that a Task runs shortly after its delay expires.
robliao7d2bb1e2017-05-26 06:33:43 +0900311TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest, PostDelayedTask) {
robliao19e3ad72017-03-11 05:21:29 +0900312 TimeTicks start_time = TimeTicks::Now();
313
314 // Post a task with a short delay.
315 WaitableEvent task_ran(WaitableEvent::ResetPolicy::MANUAL,
316 WaitableEvent::InitialState::NOT_SIGNALED);
Gabriel Charettee1640632018-01-19 01:56:31 +0900317 auto task_runner =
318 single_thread_task_runner_manager_
319 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits(), GetParam());
robliao19e3ad72017-03-11 05:21:29 +0900320 EXPECT_TRUE(task_runner->PostDelayedTask(
tzik6bdbeb22017-04-12 00:00:44 +0900321 FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&task_ran)),
robliao19e3ad72017-03-11 05:21:29 +0900322 TestTimeouts::tiny_timeout()));
323
324 // Wait until the task runs.
325 task_ran.Wait();
326
327 // Expect the task to run after its delay expires, but not more than 250 ms
328 // after that.
329 const TimeDelta actual_delay = TimeTicks::Now() - start_time;
330 EXPECT_GE(actual_delay, TestTimeouts::tiny_timeout());
331 EXPECT_LT(actual_delay,
332 TimeDelta::FromMilliseconds(250) + TestTimeouts::tiny_timeout());
333}
334
Gabriel Charettec37bf442017-09-21 11:26:13 +0900335// Verify that posting tasks after the single-thread manager is destroyed fails
336// but doesn't crash.
337TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest,
338 PostTaskAfterDestroy) {
Gabriel Charettee1640632018-01-19 01:56:31 +0900339 auto task_runner =
340 single_thread_task_runner_manager_
341 ->CreateSingleThreadTaskRunnerWithTraits(TaskTraits(), GetParam());
Peter Kasting24efe5e2018-02-24 09:03:01 +0900342 EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing()));
Gabriel Charettec37bf442017-09-21 11:26:13 +0900343 task_tracker_.Shutdown();
344 TearDownSingleThreadTaskRunnerManager();
345 EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun)));
346}
347
robliao7d2bb1e2017-05-26 06:33:43 +0900348INSTANTIATE_TEST_CASE_P(
349 AllModes,
350 TaskSchedulerSingleThreadTaskRunnerManagerCommonTest,
351 ::testing::Values(SingleThreadTaskRunnerThreadMode::SHARED,
352 SingleThreadTaskRunnerThreadMode::DEDICATED));
robliao19e3ad72017-03-11 05:21:29 +0900353
354namespace {
355
356class CallJoinFromDifferentThread : public SimpleThread {
357 public:
358 CallJoinFromDifferentThread(
359 SchedulerSingleThreadTaskRunnerManager* manager_to_join)
360 : SimpleThread("SchedulerSingleThreadTaskRunnerManagerJoinThread"),
361 manager_to_join_(manager_to_join),
362 run_started_event_(WaitableEvent::ResetPolicy::MANUAL,
363 WaitableEvent::InitialState::NOT_SIGNALED) {}
364
365 ~CallJoinFromDifferentThread() override = default;
366
367 void Run() override {
368 run_started_event_.Signal();
369 manager_to_join_->JoinForTesting();
370 }
371
372 void WaitForRunToStart() { run_started_event_.Wait(); }
373
374 private:
375 SchedulerSingleThreadTaskRunnerManager* const manager_to_join_;
376 WaitableEvent run_started_event_;
robliaoe6d9a482017-03-17 02:54:30 +0900377
robliao19e3ad72017-03-11 05:21:29 +0900378 DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread);
379};
380
381class TaskSchedulerSingleThreadTaskRunnerManagerJoinTest
382 : public TaskSchedulerSingleThreadTaskRunnerManagerTest {
383 public:
384 TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() = default;
385 ~TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() override = default;
386
387 protected:
388 void TearDownSingleThreadTaskRunnerManager() override {
389 // The tests themselves are responsible for calling JoinForTesting().
390 single_thread_task_runner_manager_.reset();
391 }
392
393 private:
394 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest);
395};
396
397} // namespace
398
399TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) {
robliaoe6d9a482017-03-17 02:54:30 +0900400 // Exercises the codepath where the workers are unavailable for unregistration
401 // because of a Join call.
robliao19e3ad72017-03-11 05:21:29 +0900402 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL,
403 WaitableEvent::InitialState::NOT_SIGNALED);
404 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL,
405 WaitableEvent::InitialState::NOT_SIGNALED);
406
407 {
robliao7d2bb1e2017-05-26 06:33:43 +0900408 auto task_runner = single_thread_task_runner_manager_
409 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900410 {WithBaseSyncPrimitives()},
robliao7d2bb1e2017-05-26 06:33:43 +0900411 SingleThreadTaskRunnerThreadMode::DEDICATED);
robliao19e3ad72017-03-11 05:21:29 +0900412 EXPECT_TRUE(task_runner->PostTask(
tzik6bdbeb22017-04-12 00:00:44 +0900413 FROM_HERE,
414 BindOnce(&WaitableEvent::Signal, Unretained(&task_running))));
robliao19e3ad72017-03-11 05:21:29 +0900415 EXPECT_TRUE(task_runner->PostTask(
tzik6bdbeb22017-04-12 00:00:44 +0900416 FROM_HERE, BindOnce(&WaitableEvent::Wait, Unretained(&task_blocking))));
robliao19e3ad72017-03-11 05:21:29 +0900417 }
418
419 task_running.Wait();
420 CallJoinFromDifferentThread join_from_different_thread(
421 single_thread_task_runner_manager_.get());
422 join_from_different_thread.Start();
423 join_from_different_thread.WaitForRunToStart();
424 task_blocking.Signal();
425 join_from_different_thread.Join();
426}
427
428TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest,
429 ConcurrentJoinExtraSkippedTask) {
robliaoe6d9a482017-03-17 02:54:30 +0900430 // Tests to make sure that tasks are properly cleaned up at Join, allowing
431 // SingleThreadTaskRunners to unregister themselves.
robliao19e3ad72017-03-11 05:21:29 +0900432 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL,
433 WaitableEvent::InitialState::NOT_SIGNALED);
434 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL,
435 WaitableEvent::InitialState::NOT_SIGNALED);
436
437 {
robliao7d2bb1e2017-05-26 06:33:43 +0900438 auto task_runner = single_thread_task_runner_manager_
439 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900440 {WithBaseSyncPrimitives()},
robliao7d2bb1e2017-05-26 06:33:43 +0900441 SingleThreadTaskRunnerThreadMode::DEDICATED);
robliao19e3ad72017-03-11 05:21:29 +0900442 EXPECT_TRUE(task_runner->PostTask(
tzik6bdbeb22017-04-12 00:00:44 +0900443 FROM_HERE,
444 BindOnce(&WaitableEvent::Signal, Unretained(&task_running))));
robliao19e3ad72017-03-11 05:21:29 +0900445 EXPECT_TRUE(task_runner->PostTask(
tzik6bdbeb22017-04-12 00:00:44 +0900446 FROM_HERE, BindOnce(&WaitableEvent::Wait, Unretained(&task_blocking))));
Peter Kasting24efe5e2018-02-24 09:03:01 +0900447 EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing()));
robliao19e3ad72017-03-11 05:21:29 +0900448 }
449
450 task_running.Wait();
451 CallJoinFromDifferentThread join_from_different_thread(
452 single_thread_task_runner_manager_.get());
453 join_from_different_thread.Start();
454 join_from_different_thread.WaitForRunToStart();
455 task_blocking.Signal();
456 join_from_different_thread.Join();
457}
458
robliaof81c0002017-03-23 07:30:15 +0900459#if defined(OS_WIN)
460
robliao7d2bb1e2017-05-26 06:33:43 +0900461TEST_P(TaskSchedulerSingleThreadTaskRunnerManagerCommonTest,
462 COMSTAInitialized) {
robliaof81c0002017-03-23 07:30:15 +0900463 scoped_refptr<SingleThreadTaskRunner> com_task_runner =
464 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900465 {TaskShutdownBehavior::BLOCK_SHUTDOWN}, GetParam());
robliaof81c0002017-03-23 07:30:15 +0900466
Robert Liaob01a9972017-07-07 09:54:14 +0900467 com_task_runner->PostTask(FROM_HERE, BindOnce(&win::AssertComApartmentType,
468 win::ComApartmentType::STA));
robliaof81c0002017-03-23 07:30:15 +0900469
470 task_tracker_.Shutdown();
471}
472
robliao7d2bb1e2017-05-26 06:33:43 +0900473TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, COMSTASameThreadUsed) {
474 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
475 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900476 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900477 SingleThreadTaskRunnerThreadMode::SHARED);
478 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
479 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900480 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900481 SingleThreadTaskRunnerThreadMode::SHARED);
482
483 PlatformThreadRef thread_ref_1;
484 task_runner_1->PostTask(FROM_HERE,
485 BindOnce(&CaptureThreadRef, &thread_ref_1));
486 PlatformThreadRef thread_ref_2;
487 task_runner_2->PostTask(FROM_HERE,
488 BindOnce(&CaptureThreadRef, &thread_ref_2));
489
490 task_tracker_.Shutdown();
491
492 ASSERT_FALSE(thread_ref_1.is_null());
493 ASSERT_FALSE(thread_ref_2.is_null());
494 EXPECT_EQ(thread_ref_1, thread_ref_2);
495}
496
robliaof81c0002017-03-23 07:30:15 +0900497namespace {
498
499const wchar_t* const kTestWindowClassName =
500 L"TaskSchedulerSingleThreadTaskRunnerManagerTestWinMessageWindow";
501
502class TaskSchedulerSingleThreadTaskRunnerManagerTestWin
503 : public TaskSchedulerSingleThreadTaskRunnerManagerTest {
504 public:
505 TaskSchedulerSingleThreadTaskRunnerManagerTestWin() = default;
506
507 void SetUp() override {
508 TaskSchedulerSingleThreadTaskRunnerManagerTest::SetUp();
509 register_class_succeeded_ = RegisterTestWindowClass();
510 ASSERT_TRUE(register_class_succeeded_);
511 }
512
513 void TearDown() override {
514 if (register_class_succeeded_)
515 ::UnregisterClass(kTestWindowClassName, CURRENT_MODULE());
516
517 TaskSchedulerSingleThreadTaskRunnerManagerTest::TearDown();
518 }
519
520 HWND CreateTestWindow() {
521 return CreateWindow(kTestWindowClassName, kTestWindowClassName, 0, 0, 0, 0,
522 0, HWND_MESSAGE, nullptr, CURRENT_MODULE(), nullptr);
523 }
524
525 private:
526 bool RegisterTestWindowClass() {
527 WNDCLASSEX window_class = {};
528 window_class.cbSize = sizeof(window_class);
529 window_class.lpfnWndProc = &::DefWindowProc;
530 window_class.hInstance = CURRENT_MODULE();
531 window_class.lpszClassName = kTestWindowClassName;
532 return !!::RegisterClassEx(&window_class);
533 }
534
535 bool register_class_succeeded_ = false;
536
537 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTestWin);
538};
539
540} // namespace
541
542TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTestWin, PumpsMessages) {
543 scoped_refptr<SingleThreadTaskRunner> com_task_runner =
544 single_thread_task_runner_manager_->CreateCOMSTATaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900545 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
robliao7d2bb1e2017-05-26 06:33:43 +0900546 SingleThreadTaskRunnerThreadMode::DEDICATED);
robliaof81c0002017-03-23 07:30:15 +0900547 HWND hwnd = nullptr;
548 // HWNDs process messages on the thread that created them, so we have to
549 // create them within the context of the task runner to properly simulate a
550 // COM callback.
551 com_task_runner->PostTask(
552 FROM_HERE,
fdoray066b38f2017-04-19 22:42:24 +0900553 BindOnce(
554 [](TaskSchedulerSingleThreadTaskRunnerManagerTestWin* test_harness,
555 HWND* hwnd) { *hwnd = test_harness->CreateTestWindow(); },
556 Unretained(this), &hwnd));
robliaof81c0002017-03-23 07:30:15 +0900557
Robert Liaoe25acff2018-01-25 07:39:17 +0900558 task_tracker_.FlushForTesting();
robliaof81c0002017-03-23 07:30:15 +0900559
560 ASSERT_NE(hwnd, nullptr);
561 // If the message pump isn't running, we will hang here. This simulates how
562 // COM would receive a callback with its own message HWND.
563 SendMessage(hwnd, WM_USER, 0, 0);
564
565 com_task_runner->PostTask(
fdoray066b38f2017-04-19 22:42:24 +0900566 FROM_HERE, BindOnce([](HWND hwnd) { ::DestroyWindow(hwnd); }, hwnd));
robliaof81c0002017-03-23 07:30:15 +0900567
568 task_tracker_.Shutdown();
569}
570
571#endif // defined(OS_WIN)
572
fdorayd952d8e2017-04-19 09:37:26 +0900573namespace {
574
575class TaskSchedulerSingleThreadTaskRunnerManagerStartTest
576 : public TaskSchedulerSingleThreadTaskRunnerManagerTest {
577 public:
578 TaskSchedulerSingleThreadTaskRunnerManagerStartTest() = default;
579
580 private:
581 void StartSingleThreadTaskRunnerManagerFromSetUp() override {
582 // Start() is called in the test body rather than in SetUp().
583 }
584
585 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerStartTest);
586};
587
588} // namespace
589
590// Verify that a task posted before Start() doesn't run until Start() is called.
591TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerStartTest,
Robert Liaob029d532017-11-17 04:00:28 +0900592 PostTaskBeforeStart) {
fdorayd952d8e2017-04-19 09:37:26 +0900593 AtomicFlag manager_started;
Robert Liaob029d532017-11-17 04:00:28 +0900594 WaitableEvent task_finished(WaitableEvent::ResetPolicy::MANUAL,
595 WaitableEvent::InitialState::NOT_SIGNALED);
fdorayd952d8e2017-04-19 09:37:26 +0900596 single_thread_task_runner_manager_
robliao7d2bb1e2017-05-26 06:33:43 +0900597 ->CreateSingleThreadTaskRunnerWithTraits(
Gabriel Charettee1640632018-01-19 01:56:31 +0900598 TaskTraits(), SingleThreadTaskRunnerThreadMode::DEDICATED)
fdorayd952d8e2017-04-19 09:37:26 +0900599 ->PostTask(
600 FROM_HERE,
fdoray066b38f2017-04-19 22:42:24 +0900601 BindOnce(
Robert Liaob029d532017-11-17 04:00:28 +0900602 [](WaitableEvent* task_finished, AtomicFlag* manager_started) {
fdorayd952d8e2017-04-19 09:37:26 +0900603 // The task should not run before Start().
604 EXPECT_TRUE(manager_started->IsSet());
Robert Liaob029d532017-11-17 04:00:28 +0900605 task_finished->Signal();
fdorayd952d8e2017-04-19 09:37:26 +0900606 },
Robert Liaob029d532017-11-17 04:00:28 +0900607 Unretained(&task_finished), Unretained(&manager_started)));
fdorayd952d8e2017-04-19 09:37:26 +0900608
Francois Doray5f643432017-10-12 01:27:12 +0900609 // Wait a little bit to make sure that the task doesn't run before start.
610 // Note: This test won't catch a case where the task runs between setting
611 // |manager_started| and calling Start(). However, we expect the test to be
612 // flaky if the tested code allows that to happen.
fdorayd952d8e2017-04-19 09:37:26 +0900613 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
614 manager_started.Set();
615 single_thread_task_runner_manager_->Start();
616
Robert Liaob029d532017-11-17 04:00:28 +0900617 // Wait for the task to complete to keep |manager_started| alive.
618 task_finished.Wait();
fdorayd952d8e2017-04-19 09:37:26 +0900619}
620
robliao19e3ad72017-03-11 05:21:29 +0900621} // namespace internal
622} // namespace base