1 // Copyright 2017 The Chromium Authors
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/thread_pool/pooled_single_thread_task_runner_manager.h"
6
7 #include "base/functional/bind.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/synchronization/atomic_flag.h"
12 #include "base/synchronization/lock.h"
13 #include "base/task/task_traits.h"
14 #include "base/task/thread_pool/can_run_policy_test.h"
15 #include "base/task/thread_pool/delayed_task_manager.h"
16 #include "base/task/thread_pool/environment_config.h"
17 #include "base/task/thread_pool/task_tracker.h"
18 #include "base/task/thread_pool/test_utils.h"
19 #include "base/test/bind.h"
20 #include "base/test/gtest_util.h"
21 #include "base/test/scoped_feature_list.h"
22 #include "base/test/test_timeouts.h"
23 #include "base/test/test_waitable_event.h"
24 #include "base/threading/platform_thread.h"
25 #include "base/threading/simple_thread.h"
26 #include "base/threading/thread.h"
27 #include "base/threading/thread_restrictions.h"
28 #include "build/build_config.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 #if BUILDFLAG(IS_WIN)
32 #include <windows.h>
33
34 #include "base/win/com_init_util.h"
35 #include "base/win/current_module.h"
36 #endif // BUILDFLAG(IS_WIN)
37
38 namespace base {
39 namespace internal {
40
41 namespace {
42
43 class PooledSingleThreadTaskRunnerManagerTest : public testing::Test {
44 public:
45 PooledSingleThreadTaskRunnerManagerTest(
46 const PooledSingleThreadTaskRunnerManagerTest&) = delete;
47 PooledSingleThreadTaskRunnerManagerTest& operator=(
48 const PooledSingleThreadTaskRunnerManagerTest&) = delete;
49
50 protected:
51 PooledSingleThreadTaskRunnerManagerTest() = default;
52
SetUp()53 void SetUp() override {
54 service_thread_.Start();
55 delayed_task_manager_.Start(service_thread_.task_runner());
56 single_thread_task_runner_manager_ =
57 std::make_unique<PooledSingleThreadTaskRunnerManager>(
58 task_tracker_.GetTrackedRef(), &delayed_task_manager_);
59 StartSingleThreadTaskRunnerManagerFromSetUp();
60 }
61
TearDown()62 void TearDown() override {
63 if (single_thread_task_runner_manager_)
64 TearDownSingleThreadTaskRunnerManager();
65 delayed_task_manager_.Shutdown();
66 service_thread_.Stop();
67 }
68
StartSingleThreadTaskRunnerManagerFromSetUp()69 virtual void StartSingleThreadTaskRunnerManagerFromSetUp() {
70 single_thread_task_runner_manager_->Start(service_thread_.task_runner());
71 }
72
TearDownSingleThreadTaskRunnerManager()73 virtual void TearDownSingleThreadTaskRunnerManager() {
74 single_thread_task_runner_manager_->JoinForTesting();
75 single_thread_task_runner_manager_.reset();
76 }
77
78 Thread service_thread_{"ThreadPoolServiceThread"};
79 TaskTracker task_tracker_;
80 DelayedTaskManager delayed_task_manager_;
81 std::unique_ptr<PooledSingleThreadTaskRunnerManager>
82 single_thread_task_runner_manager_;
83 };
84
CaptureThreadRef(PlatformThreadRef * thread_ref)85 void CaptureThreadRef(PlatformThreadRef* thread_ref) {
86 ASSERT_TRUE(thread_ref);
87 *thread_ref = PlatformThread::CurrentRef();
88 }
89
ShouldNotRun()90 void ShouldNotRun() {
91 ADD_FAILURE() << "Ran a task that shouldn't run.";
92 }
93
94 } // namespace
95
TEST_F(PooledSingleThreadTaskRunnerManagerTest,DifferentThreadsUsed)96 TEST_F(PooledSingleThreadTaskRunnerManagerTest, DifferentThreadsUsed) {
97 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
98 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
99 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
100 SingleThreadTaskRunnerThreadMode::DEDICATED);
101 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
102 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
103 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
104 SingleThreadTaskRunnerThreadMode::DEDICATED);
105
106 PlatformThreadRef thread_ref_1;
107 task_runner_1->PostTask(FROM_HERE,
108 BindOnce(&CaptureThreadRef, &thread_ref_1));
109 PlatformThreadRef thread_ref_2;
110 task_runner_2->PostTask(FROM_HERE,
111 BindOnce(&CaptureThreadRef, &thread_ref_2));
112
113 test::ShutdownTaskTracker(&task_tracker_);
114
115 ASSERT_FALSE(thread_ref_1.is_null());
116 ASSERT_FALSE(thread_ref_2.is_null());
117 EXPECT_NE(thread_ref_1, thread_ref_2);
118 }
119
TEST_F(PooledSingleThreadTaskRunnerManagerTest,SameThreadUsed)120 TEST_F(PooledSingleThreadTaskRunnerManagerTest, SameThreadUsed) {
121 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
122 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
123 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
124 SingleThreadTaskRunnerThreadMode::SHARED);
125 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
126 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
127 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
128 SingleThreadTaskRunnerThreadMode::SHARED);
129
130 PlatformThreadRef thread_ref_1;
131 task_runner_1->PostTask(FROM_HERE,
132 BindOnce(&CaptureThreadRef, &thread_ref_1));
133 PlatformThreadRef thread_ref_2;
134 task_runner_2->PostTask(FROM_HERE,
135 BindOnce(&CaptureThreadRef, &thread_ref_2));
136
137 test::ShutdownTaskTracker(&task_tracker_);
138
139 ASSERT_FALSE(thread_ref_1.is_null());
140 ASSERT_FALSE(thread_ref_2.is_null());
141 EXPECT_EQ(thread_ref_1, thread_ref_2);
142 }
143
TEST_F(PooledSingleThreadTaskRunnerManagerTest,RunsTasksInCurrentSequence)144 TEST_F(PooledSingleThreadTaskRunnerManagerTest, RunsTasksInCurrentSequence) {
145 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
146 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
147 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
148 SingleThreadTaskRunnerThreadMode::DEDICATED);
149 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
150 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
151 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
152 SingleThreadTaskRunnerThreadMode::DEDICATED);
153
154 EXPECT_FALSE(task_runner_1->RunsTasksInCurrentSequence());
155 EXPECT_FALSE(task_runner_2->RunsTasksInCurrentSequence());
156
157 task_runner_1->PostTask(
158 FROM_HERE,
159 BindOnce(
160 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1,
161 scoped_refptr<SingleThreadTaskRunner> task_runner_2) {
162 EXPECT_TRUE(task_runner_1->RunsTasksInCurrentSequence());
163 EXPECT_FALSE(task_runner_2->RunsTasksInCurrentSequence());
164 },
165 task_runner_1, task_runner_2));
166
167 task_runner_2->PostTask(
168 FROM_HERE,
169 BindOnce(
170 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1,
171 scoped_refptr<SingleThreadTaskRunner> task_runner_2) {
172 EXPECT_FALSE(task_runner_1->RunsTasksInCurrentSequence());
173 EXPECT_TRUE(task_runner_2->RunsTasksInCurrentSequence());
174 },
175 task_runner_1, task_runner_2));
176
177 test::ShutdownTaskTracker(&task_tracker_);
178 }
179
TEST_F(PooledSingleThreadTaskRunnerManagerTest,SharedWithBaseSyncPrimitivesDCHECKs)180 TEST_F(PooledSingleThreadTaskRunnerManagerTest,
181 SharedWithBaseSyncPrimitivesDCHECKs) {
182 GTEST_FLAG_SET(death_test_style, "threadsafe");
183 EXPECT_DCHECK_DEATH({
184 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
185 {WithBaseSyncPrimitives()}, SingleThreadTaskRunnerThreadMode::SHARED);
186 });
187 }
188
189 // Regression test for https://crbug.com/829786
TEST_F(PooledSingleThreadTaskRunnerManagerTest,ContinueOnShutdownDoesNotBlockBlockShutdown)190 TEST_F(PooledSingleThreadTaskRunnerManagerTest,
191 ContinueOnShutdownDoesNotBlockBlockShutdown) {
192 TestWaitableEvent task_has_started;
193 TestWaitableEvent task_can_continue;
194
195 // Post a CONTINUE_ON_SHUTDOWN task that waits on
196 // |task_can_continue| to a shared SingleThreadTaskRunner.
197 single_thread_task_runner_manager_
198 ->CreateSingleThreadTaskRunner(
199 {TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
200 SingleThreadTaskRunnerThreadMode::SHARED)
201 ->PostTask(FROM_HERE, base::BindLambdaForTesting([&]() {
202 task_has_started.Signal();
203 task_can_continue.Wait();
204 }));
205
206 task_has_started.Wait();
207
208 // Post a BLOCK_SHUTDOWN task to a shared SingleThreadTaskRunner.
209 single_thread_task_runner_manager_
210 ->CreateSingleThreadTaskRunner({TaskShutdownBehavior::BLOCK_SHUTDOWN},
211 SingleThreadTaskRunnerThreadMode::SHARED)
212 ->PostTask(FROM_HERE, DoNothing());
213
214 // Shutdown should not hang even though the first task hasn't finished.
215 test::ShutdownTaskTracker(&task_tracker_);
216
217 // Let the first task finish.
218 task_can_continue.Signal();
219
220 // Tear down from the test body to prevent accesses to |task_can_continue|
221 // after it goes out of scope.
222 TearDownSingleThreadTaskRunnerManager();
223 }
224
225 namespace {
226
227 class PooledSingleThreadTaskRunnerManagerCommonTest
228 : public PooledSingleThreadTaskRunnerManagerTest,
229 public ::testing::WithParamInterface<
230 std::tuple<SingleThreadTaskRunnerThreadMode,
231 bool /* enable_utility_threads */>> {
232 public:
PooledSingleThreadTaskRunnerManagerCommonTest()233 PooledSingleThreadTaskRunnerManagerCommonTest() {
234 if (std::get<1>(GetParam())) {
235 feature_list_.InitWithFeatures({kUseUtilityThreadGroup}, {});
236 }
237 }
238 PooledSingleThreadTaskRunnerManagerCommonTest(
239 const PooledSingleThreadTaskRunnerManagerCommonTest&) = delete;
240 PooledSingleThreadTaskRunnerManagerCommonTest& operator=(
241 const PooledSingleThreadTaskRunnerManagerCommonTest&) = delete;
242
CreateTaskRunner(TaskTraits traits={})243 scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner(
244 TaskTraits traits = {}) {
245 return single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
246 traits, GetSingleThreadTaskRunnerThreadMode());
247 }
248
GetSingleThreadTaskRunnerThreadMode() const249 SingleThreadTaskRunnerThreadMode GetSingleThreadTaskRunnerThreadMode() const {
250 return std::get<0>(GetParam());
251 }
252
253 protected:
254 const bool use_utility_thread_group_ =
255 CanUseUtilityThreadTypeForWorkerThread() && std::get<1>(GetParam());
256 base::test::ScopedFeatureList feature_list_;
257 };
258
259 } // namespace
260
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,ThreadTypeSetCorrectly)261 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, ThreadTypeSetCorrectly) {
262 const struct {
263 TaskTraits traits;
264 ThreadType expected_thread_type;
265 } test_cases[] = {
266 {{TaskPriority::BEST_EFFORT},
267 CanUseBackgroundThreadTypeForWorkerThread() ? ThreadType::kBackground
268 : use_utility_thread_group_ ? ThreadType::kUtility
269 : ThreadType::kDefault},
270 {{TaskPriority::BEST_EFFORT, ThreadPolicy::PREFER_BACKGROUND},
271 CanUseBackgroundThreadTypeForWorkerThread() ? ThreadType::kBackground
272 : use_utility_thread_group_ ? ThreadType::kUtility
273 : ThreadType::kDefault},
274 {{TaskPriority::BEST_EFFORT, ThreadPolicy::MUST_USE_FOREGROUND},
275 ThreadType::kDefault},
276 {{TaskPriority::USER_VISIBLE},
277 use_utility_thread_group_ ? ThreadType::kUtility : ThreadType::kDefault},
278 {{TaskPriority::USER_VISIBLE, ThreadPolicy::PREFER_BACKGROUND},
279 use_utility_thread_group_ ? ThreadType::kUtility : ThreadType::kDefault},
280 {{TaskPriority::USER_VISIBLE, ThreadPolicy::MUST_USE_FOREGROUND},
281 ThreadType::kDefault},
282 {{TaskPriority::USER_BLOCKING}, ThreadType::kDefault},
283 {{TaskPriority::USER_BLOCKING, ThreadPolicy::PREFER_BACKGROUND},
284 ThreadType::kDefault},
285 {{TaskPriority::USER_BLOCKING, ThreadPolicy::MUST_USE_FOREGROUND},
286 ThreadType::kDefault}};
287
288 // Why are events used here instead of the task tracker?
289 // Shutting down can cause priorities to get raised. This means we have to use
290 // events to determine when a task is run.
291 for (auto& test_case : test_cases) {
292 TestWaitableEvent event;
293 CreateTaskRunner(test_case.traits)
294 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
295 EXPECT_EQ(test_case.expected_thread_type,
296 PlatformThread::GetCurrentThreadType());
297 event.Signal();
298 }));
299 event.Wait();
300 }
301 }
302
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,ThreadNamesSet)303 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, ThreadNamesSet) {
304 const std::string maybe_shared(
305 GetSingleThreadTaskRunnerThreadMode() ==
306 SingleThreadTaskRunnerThreadMode::DEDICATED
307 ? ""
308 : "Shared");
309 const std::string background =
310 "^ThreadPoolSingleThread" + maybe_shared + "Background\\d+$";
311 const std::string utility =
312 "^ThreadPoolSingleThread" + maybe_shared + "Utility\\d+$";
313 const std::string foreground =
314 "^ThreadPoolSingleThread" + maybe_shared + "Foreground\\d+$";
315 const std::string background_blocking =
316 "^ThreadPoolSingleThread" + maybe_shared + "BackgroundBlocking\\d+$";
317 const std::string utility_blocking =
318 "^ThreadPoolSingleThread" + maybe_shared + "UtilityBlocking\\d+$";
319 const std::string foreground_blocking =
320 "^ThreadPoolSingleThread" + maybe_shared + "ForegroundBlocking\\d+$";
321
322 const struct {
323 TaskTraits traits;
324 std::string expected_thread_name;
325 } test_cases[] = {
326 // Non-MayBlock()
327 {{TaskPriority::BEST_EFFORT},
328 CanUseBackgroundThreadTypeForWorkerThread() ? background
329 : use_utility_thread_group_ ? utility
330 : foreground},
331 {{TaskPriority::BEST_EFFORT, ThreadPolicy::PREFER_BACKGROUND},
332 CanUseBackgroundThreadTypeForWorkerThread() ? background
333 : use_utility_thread_group_ ? utility
334 : foreground},
335 {{TaskPriority::BEST_EFFORT, ThreadPolicy::MUST_USE_FOREGROUND},
336 foreground},
337 {{TaskPriority::USER_VISIBLE},
338 use_utility_thread_group_ ? utility : foreground},
339 {{TaskPriority::USER_VISIBLE, ThreadPolicy::PREFER_BACKGROUND},
340 use_utility_thread_group_ ? utility : foreground},
341 {{TaskPriority::USER_VISIBLE, ThreadPolicy::MUST_USE_FOREGROUND},
342 foreground},
343 {{TaskPriority::USER_BLOCKING}, foreground},
344 {{TaskPriority::USER_BLOCKING, ThreadPolicy::PREFER_BACKGROUND},
345 foreground},
346 {{TaskPriority::USER_BLOCKING, ThreadPolicy::MUST_USE_FOREGROUND},
347 foreground},
348
349 // MayBlock()
350 {{TaskPriority::BEST_EFFORT, MayBlock()},
351 CanUseBackgroundThreadTypeForWorkerThread() ? background_blocking
352 : use_utility_thread_group_ ? utility_blocking
353 : foreground_blocking},
354 {{TaskPriority::BEST_EFFORT, ThreadPolicy::PREFER_BACKGROUND, MayBlock()},
355 CanUseBackgroundThreadTypeForWorkerThread() ? background_blocking
356 : use_utility_thread_group_ ? utility_blocking
357 : foreground_blocking},
358 {{TaskPriority::BEST_EFFORT, ThreadPolicy::MUST_USE_FOREGROUND,
359 MayBlock()},
360 foreground_blocking},
361 {{TaskPriority::USER_VISIBLE, MayBlock()},
362 use_utility_thread_group_ ? utility_blocking : foreground_blocking},
363 {{TaskPriority::USER_VISIBLE, ThreadPolicy::PREFER_BACKGROUND,
364 MayBlock()},
365 use_utility_thread_group_ ? utility_blocking : foreground_blocking},
366 {{TaskPriority::USER_VISIBLE, ThreadPolicy::MUST_USE_FOREGROUND,
367 MayBlock()},
368
369 foreground_blocking},
370 {{TaskPriority::USER_BLOCKING, MayBlock()}, foreground_blocking},
371 {{TaskPriority::USER_BLOCKING, ThreadPolicy::PREFER_BACKGROUND,
372 MayBlock()},
373 foreground_blocking},
374 {{TaskPriority::USER_BLOCKING, ThreadPolicy::MUST_USE_FOREGROUND,
375 MayBlock()},
376 foreground_blocking}};
377
378 for (auto& test_case : test_cases) {
379 TestWaitableEvent event;
380 CreateTaskRunner(test_case.traits)
381 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
382 EXPECT_THAT(PlatformThread::GetName(),
383 ::testing::MatchesRegex(
384 test_case.expected_thread_name));
385 event.Signal();
386 }));
387 event.Wait();
388 }
389 }
390
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,PostTaskAfterShutdown)391 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, PostTaskAfterShutdown) {
392 auto task_runner = CreateTaskRunner();
393 test::ShutdownTaskTracker(&task_tracker_);
394 EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun)));
395 }
396
397 // Verify that a Task runs shortly after its delay expires.
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,PostDelayedTask)398 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, PostDelayedTask) {
399 TestWaitableEvent task_ran(WaitableEvent::ResetPolicy::AUTOMATIC);
400 auto task_runner = CreateTaskRunner();
401
402 // Wait until the task runner is up and running to make sure the test below is
403 // solely timing the delayed task, not bringing up a physical thread.
404 task_runner->PostTask(
405 FROM_HERE, BindOnce(&TestWaitableEvent::Signal, Unretained(&task_ran)));
406 task_ran.Wait();
407 ASSERT_TRUE(!task_ran.IsSignaled());
408
409
410 // Post a task with a short delay.
411 const TimeTicks start_time = TimeTicks::Now();
412 EXPECT_TRUE(task_runner->PostDelayedTask(
413 FROM_HERE, BindOnce(&TestWaitableEvent::Signal, Unretained(&task_ran)),
414 TestTimeouts::tiny_timeout()));
415
416 // Wait until the task runs.
417 task_ran.Wait();
418
419 // Expect the task to run after its delay expires, but no more than a
420 // reasonable amount of time after that (overloaded bots can be slow sometimes
421 // so give it 10X flexibility).
422 const TimeDelta actual_delay = TimeTicks::Now() - start_time;
423 EXPECT_GE(actual_delay, TestTimeouts::tiny_timeout());
424 EXPECT_LT(actual_delay, 10 * TestTimeouts::tiny_timeout());
425 }
426
427 // Verify that posting tasks after the single-thread manager is destroyed fails
428 // but doesn't crash.
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,PostTaskAfterDestroy)429 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, PostTaskAfterDestroy) {
430 auto task_runner = CreateTaskRunner();
431 EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing()));
432 test::ShutdownTaskTracker(&task_tracker_);
433 TearDownSingleThreadTaskRunnerManager();
434 EXPECT_FALSE(task_runner->PostTask(FROM_HERE, BindOnce(&ShouldNotRun)));
435 }
436
437 // Verify that tasks only run when allowed by the CanRunPolicy.
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,CanRunPolicyBasic)438 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, CanRunPolicyBasic) {
439 test::TestCanRunPolicyBasic(
440 single_thread_task_runner_manager_.get(),
441 [this](TaskPriority priority) { return CreateTaskRunner({priority}); },
442 &task_tracker_);
443 }
444
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,CanRunPolicyUpdatedBeforeRun)445 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,
446 CanRunPolicyUpdatedBeforeRun) {
447 test::TestCanRunPolicyChangedBeforeRun(
448 single_thread_task_runner_manager_.get(),
449 [this](TaskPriority priority) { return CreateTaskRunner({priority}); },
450 &task_tracker_);
451 }
452
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,CanRunPolicyLoad)453 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, CanRunPolicyLoad) {
454 test::TestCanRunPolicyLoad(
455 single_thread_task_runner_manager_.get(),
456 [this](TaskPriority priority) { return CreateTaskRunner({priority}); },
457 &task_tracker_);
458 }
459
460 INSTANTIATE_TEST_SUITE_P(
461 SharedAndDedicated,
462 PooledSingleThreadTaskRunnerManagerCommonTest,
463 ::testing::Combine(
464 ::testing::Values(SingleThreadTaskRunnerThreadMode::SHARED,
465 SingleThreadTaskRunnerThreadMode::DEDICATED),
466 ::testing::Values(false, true)));
467
468 namespace {
469
470 class CallJoinFromDifferentThread : public SimpleThread {
471 public:
CallJoinFromDifferentThread(PooledSingleThreadTaskRunnerManager * manager_to_join)472 CallJoinFromDifferentThread(
473 PooledSingleThreadTaskRunnerManager* manager_to_join)
474 : SimpleThread("PooledSingleThreadTaskRunnerManagerJoinThread"),
475 manager_to_join_(manager_to_join) {}
476
477 CallJoinFromDifferentThread(const CallJoinFromDifferentThread&) = delete;
478 CallJoinFromDifferentThread& operator=(const CallJoinFromDifferentThread&) =
479 delete;
480 ~CallJoinFromDifferentThread() override = default;
481
Run()482 void Run() override {
483 run_started_event_.Signal();
484 manager_to_join_->JoinForTesting();
485 }
486
WaitForRunToStart()487 void WaitForRunToStart() { run_started_event_.Wait(); }
488
489 private:
490 const raw_ptr<PooledSingleThreadTaskRunnerManager> manager_to_join_;
491 TestWaitableEvent run_started_event_;
492 };
493
494 class PooledSingleThreadTaskRunnerManagerJoinTest
495 : public PooledSingleThreadTaskRunnerManagerTest {
496 public:
497 PooledSingleThreadTaskRunnerManagerJoinTest() = default;
498 PooledSingleThreadTaskRunnerManagerJoinTest(
499 const PooledSingleThreadTaskRunnerManagerJoinTest&) = delete;
500 PooledSingleThreadTaskRunnerManagerJoinTest& operator=(
501 const PooledSingleThreadTaskRunnerManagerJoinTest&) = delete;
502 ~PooledSingleThreadTaskRunnerManagerJoinTest() override = default;
503
504 protected:
TearDownSingleThreadTaskRunnerManager()505 void TearDownSingleThreadTaskRunnerManager() override {
506 // The tests themselves are responsible for calling JoinForTesting().
507 single_thread_task_runner_manager_.reset();
508 }
509 };
510
511 } // namespace
512
TEST_F(PooledSingleThreadTaskRunnerManagerJoinTest,ConcurrentJoin)513 TEST_F(PooledSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) {
514 // Exercises the codepath where the workers are unavailable for unregistration
515 // because of a Join call.
516 TestWaitableEvent task_running;
517 TestWaitableEvent task_blocking;
518
519 {
520 auto task_runner =
521 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
522 {WithBaseSyncPrimitives()},
523 SingleThreadTaskRunnerThreadMode::DEDICATED);
524 EXPECT_TRUE(task_runner->PostTask(
525 FROM_HERE,
526 BindOnce(&TestWaitableEvent::Signal, Unretained(&task_running))));
527 EXPECT_TRUE(task_runner->PostTask(
528 FROM_HERE,
529 BindOnce(&TestWaitableEvent::Wait, Unretained(&task_blocking))));
530 }
531
532 task_running.Wait();
533 CallJoinFromDifferentThread join_from_different_thread(
534 single_thread_task_runner_manager_.get());
535 join_from_different_thread.Start();
536 join_from_different_thread.WaitForRunToStart();
537 task_blocking.Signal();
538 join_from_different_thread.Join();
539 }
540
TEST_F(PooledSingleThreadTaskRunnerManagerJoinTest,ConcurrentJoinExtraSkippedTask)541 TEST_F(PooledSingleThreadTaskRunnerManagerJoinTest,
542 ConcurrentJoinExtraSkippedTask) {
543 // Tests to make sure that tasks are properly cleaned up at Join, allowing
544 // SingleThreadTaskRunners to unregister themselves.
545 TestWaitableEvent task_running;
546 TestWaitableEvent task_blocking;
547
548 {
549 auto task_runner =
550 single_thread_task_runner_manager_->CreateSingleThreadTaskRunner(
551 {WithBaseSyncPrimitives()},
552 SingleThreadTaskRunnerThreadMode::DEDICATED);
553 EXPECT_TRUE(task_runner->PostTask(
554 FROM_HERE,
555 BindOnce(&TestWaitableEvent::Signal, Unretained(&task_running))));
556 EXPECT_TRUE(task_runner->PostTask(
557 FROM_HERE,
558 BindOnce(&TestWaitableEvent::Wait, Unretained(&task_blocking))));
559 EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing()));
560 }
561
562 task_running.Wait();
563 CallJoinFromDifferentThread join_from_different_thread(
564 single_thread_task_runner_manager_.get());
565 join_from_different_thread.Start();
566 join_from_different_thread.WaitForRunToStart();
567 task_blocking.Signal();
568 join_from_different_thread.Join();
569 }
570
571 #if BUILDFLAG(IS_WIN)
572
TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest,COMSTAInitialized)573 TEST_P(PooledSingleThreadTaskRunnerManagerCommonTest, COMSTAInitialized) {
574 scoped_refptr<SingleThreadTaskRunner> com_task_runner =
575 single_thread_task_runner_manager_->CreateCOMSTATaskRunner(
576 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
577 GetSingleThreadTaskRunnerThreadMode());
578
579 com_task_runner->PostTask(FROM_HERE, BindOnce(&win::AssertComApartmentType,
580 win::ComApartmentType::STA));
581
582 test::ShutdownTaskTracker(&task_tracker_);
583 }
584
TEST_F(PooledSingleThreadTaskRunnerManagerTest,COMSTASameThreadUsed)585 TEST_F(PooledSingleThreadTaskRunnerManagerTest, COMSTASameThreadUsed) {
586 scoped_refptr<SingleThreadTaskRunner> task_runner_1 =
587 single_thread_task_runner_manager_->CreateCOMSTATaskRunner(
588 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
589 SingleThreadTaskRunnerThreadMode::SHARED);
590 scoped_refptr<SingleThreadTaskRunner> task_runner_2 =
591 single_thread_task_runner_manager_->CreateCOMSTATaskRunner(
592 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
593 SingleThreadTaskRunnerThreadMode::SHARED);
594
595 PlatformThreadRef thread_ref_1;
596 task_runner_1->PostTask(FROM_HERE,
597 BindOnce(&CaptureThreadRef, &thread_ref_1));
598 PlatformThreadRef thread_ref_2;
599 task_runner_2->PostTask(FROM_HERE,
600 BindOnce(&CaptureThreadRef, &thread_ref_2));
601
602 test::ShutdownTaskTracker(&task_tracker_);
603
604 ASSERT_FALSE(thread_ref_1.is_null());
605 ASSERT_FALSE(thread_ref_2.is_null());
606 EXPECT_EQ(thread_ref_1, thread_ref_2);
607 }
608
609 namespace {
610
611 const wchar_t* const kTestWindowClassName =
612 L"PooledSingleThreadTaskRunnerManagerTestWinMessageWindow";
613
614 class PooledSingleThreadTaskRunnerManagerTestWin
615 : public PooledSingleThreadTaskRunnerManagerTest {
616 public:
617 PooledSingleThreadTaskRunnerManagerTestWin() = default;
618 PooledSingleThreadTaskRunnerManagerTestWin(
619 const PooledSingleThreadTaskRunnerManagerTestWin&) = delete;
620 PooledSingleThreadTaskRunnerManagerTestWin& operator=(
621 const PooledSingleThreadTaskRunnerManagerTestWin&) = delete;
622
SetUp()623 void SetUp() override {
624 PooledSingleThreadTaskRunnerManagerTest::SetUp();
625 register_class_succeeded_ = RegisterTestWindowClass();
626 ASSERT_TRUE(register_class_succeeded_);
627 }
628
TearDown()629 void TearDown() override {
630 if (register_class_succeeded_)
631 ::UnregisterClass(kTestWindowClassName, CURRENT_MODULE());
632
633 PooledSingleThreadTaskRunnerManagerTest::TearDown();
634 }
635
CreateTestWindow()636 HWND CreateTestWindow() {
637 return CreateWindow(kTestWindowClassName, kTestWindowClassName, 0, 0, 0, 0,
638 0, HWND_MESSAGE, nullptr, CURRENT_MODULE(), nullptr);
639 }
640
641 private:
RegisterTestWindowClass()642 bool RegisterTestWindowClass() {
643 WNDCLASSEX window_class = {};
644 window_class.cbSize = sizeof(window_class);
645 window_class.lpfnWndProc = &::DefWindowProc;
646 window_class.hInstance = CURRENT_MODULE();
647 window_class.lpszClassName = kTestWindowClassName;
648 return !!::RegisterClassEx(&window_class);
649 }
650
651 bool register_class_succeeded_ = false;
652 };
653
654 } // namespace
655
TEST_F(PooledSingleThreadTaskRunnerManagerTestWin,PumpsMessages)656 TEST_F(PooledSingleThreadTaskRunnerManagerTestWin, PumpsMessages) {
657 scoped_refptr<SingleThreadTaskRunner> com_task_runner =
658 single_thread_task_runner_manager_->CreateCOMSTATaskRunner(
659 {TaskShutdownBehavior::BLOCK_SHUTDOWN},
660 SingleThreadTaskRunnerThreadMode::DEDICATED);
661 HWND hwnd = nullptr;
662 // HWNDs process messages on the thread that created them, so we have to
663 // create them within the context of the task runner to properly simulate a
664 // COM callback.
665 com_task_runner->PostTask(
666 FROM_HERE,
667 BindOnce([](PooledSingleThreadTaskRunnerManagerTestWin* test_harness,
668 HWND* hwnd) { *hwnd = test_harness->CreateTestWindow(); },
669 Unretained(this), &hwnd));
670
671 task_tracker_.FlushForTesting();
672
673 ASSERT_NE(hwnd, nullptr);
674 // If the message pump isn't running, we will hang here. This simulates how
675 // COM would receive a callback with its own message HWND.
676 SendMessage(hwnd, WM_USER, 0, 0);
677
678 com_task_runner->PostTask(
679 FROM_HERE, BindOnce([](HWND hwnd) { ::DestroyWindow(hwnd); }, hwnd));
680
681 test::ShutdownTaskTracker(&task_tracker_);
682 }
683
684 #endif // BUILDFLAG(IS_WIN)
685
686 namespace {
687
688 class PooledSingleThreadTaskRunnerManagerStartTest
689 : public PooledSingleThreadTaskRunnerManagerTest {
690 public:
691 PooledSingleThreadTaskRunnerManagerStartTest() = default;
692 PooledSingleThreadTaskRunnerManagerStartTest(
693 const PooledSingleThreadTaskRunnerManagerStartTest&) = delete;
694 PooledSingleThreadTaskRunnerManagerStartTest& operator=(
695 const PooledSingleThreadTaskRunnerManagerStartTest&) = delete;
696
697 private:
StartSingleThreadTaskRunnerManagerFromSetUp()698 void StartSingleThreadTaskRunnerManagerFromSetUp() override {
699 // Start() is called in the test body rather than in SetUp().
700 }
701 };
702
703 } // namespace
704
705 // Verify that a task posted before Start() doesn't run until Start() is called.
TEST_F(PooledSingleThreadTaskRunnerManagerStartTest,PostTaskBeforeStart)706 TEST_F(PooledSingleThreadTaskRunnerManagerStartTest, PostTaskBeforeStart) {
707 AtomicFlag manager_started;
708 TestWaitableEvent task_finished;
709 single_thread_task_runner_manager_
710 ->CreateSingleThreadTaskRunner(
711 {}, SingleThreadTaskRunnerThreadMode::DEDICATED)
712 ->PostTask(FROM_HERE,
713 BindOnce(
714 [](TestWaitableEvent* task_finished,
715 AtomicFlag* manager_started) {
716 // The task should not run before Start().
717 EXPECT_TRUE(manager_started->IsSet());
718 task_finished->Signal();
719 },
720 Unretained(&task_finished), Unretained(&manager_started)));
721
722 // Wait a little bit to make sure that the task doesn't run before start.
723 // Note: This test won't catch a case where the task runs between setting
724 // |manager_started| and calling Start(). However, we expect the test to be
725 // flaky if the tested code allows that to happen.
726 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
727 manager_started.Set();
728 single_thread_task_runner_manager_->Start(service_thread_.task_runner());
729
730 // Wait for the task to complete to keep |manager_started| alive.
731 task_finished.Wait();
732 }
733
734 } // namespace internal
735 } // namespace base
736