1 // Copyright 2016 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/thread_pool_impl.h"
6
7 #include <stddef.h>
8
9 #include <atomic>
10 #include <memory>
11 #include <string>
12 #include <tuple>
13 #include <utility>
14 #include <vector>
15
16 #include "base/base_switches.h"
17 #include "base/cfi_buildflags.h"
18 #include "base/containers/span.h"
19 #include "base/debug/stack_trace.h"
20 #include "base/functional/bind.h"
21 #include "base/functional/callback.h"
22 #include "base/functional/callback_helpers.h"
23 #include "base/memory/raw_ptr.h"
24 #include "base/message_loop/message_pump_type.h"
25 #include "base/metrics/field_trial.h"
26 #include "base/metrics/field_trial_params.h"
27 #include "base/strings/strcat.h"
28 #include "base/system/sys_info.h"
29 #include "base/task/post_job.h"
30 #include "base/task/task_features.h"
31 #include "base/task/task_traits.h"
32 #include "base/task/thread_pool/environment_config.h"
33 #include "base/task/thread_pool/test_task_factory.h"
34 #include "base/task/thread_pool/test_utils.h"
35 #include "base/task/thread_pool/worker_thread_observer.h"
36 #include "base/task/updateable_sequenced_task_runner.h"
37 #include "base/test/bind.h"
38 #include "base/test/gtest_util.h"
39 #include "base/test/scoped_feature_list.h"
40 #include "base/test/test_timeouts.h"
41 #include "base/test/test_waitable_event.h"
42 #include "base/threading/platform_thread.h"
43 #include "base/threading/sequence_local_storage_slot.h"
44 #include "base/threading/simple_thread.h"
45 #include "base/threading/thread.h"
46 #include "base/threading/thread_restrictions.h"
47 #include "base/time/time.h"
48 #include "build/build_config.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50
51 #if BUILDFLAG(IS_POSIX)
52 #include <unistd.h>
53
54 #include "base/debug/leak_annotations.h"
55 #include "base/files/file_descriptor_watcher_posix.h"
56 #include "base/files/file_util.h"
57 #include "base/posix/eintr_wrapper.h"
58 #endif // BUILDFLAG(IS_POSIX)
59
60 #if BUILDFLAG(IS_WIN)
61 #include "base/win/com_init_util.h"
62 #endif // BUILDFLAG(IS_WIN)
63
64 namespace base {
65 namespace internal {
66
67 namespace {
68
69 constexpr size_t kMaxNumForegroundThreads = 4;
70 constexpr size_t kMaxNumUtilityThreads = 2;
71
72 struct TraitsExecutionModePair {
TraitsExecutionModePairbase::internal::__anonf5bd97a00111::TraitsExecutionModePair73 TraitsExecutionModePair(const TaskTraits& traits,
74 TaskSourceExecutionMode execution_mode)
75 : traits(traits), execution_mode(execution_mode) {}
76
77 TaskTraits traits;
78 TaskSourceExecutionMode execution_mode;
79 };
80
81 // Returns true if a task with |traits| could run at background thread priority
82 // on this platform. Even if this returns true, it is possible that the task
83 // won't run at background thread priority if a native thread group is used.
TraitsSupportBackgroundThreadType(const TaskTraits & traits)84 bool TraitsSupportBackgroundThreadType(const TaskTraits& traits) {
85 return traits.priority() == TaskPriority::BEST_EFFORT &&
86 traits.thread_policy() == ThreadPolicy::PREFER_BACKGROUND &&
87 CanUseBackgroundThreadTypeForWorkerThread();
88 }
89
90 // Returns true if a task with |traits| could run at utility thread
91 // type on this platform. Even if this returns true, it is possible that the
92 // task won't run at efficient thread priority if a native thread group is used
93 // or the utility thread group is disabled.
TraitsSupportUtilityThreadType(const TaskTraits & traits)94 bool TraitsSupportUtilityThreadType(const TaskTraits& traits) {
95 return traits.priority() <= TaskPriority::USER_VISIBLE &&
96 traits.thread_policy() == ThreadPolicy::PREFER_BACKGROUND &&
97 CanUseUtilityThreadTypeForWorkerThread();
98 }
99
100 // Verify that the current thread type and I/O restrictions are appropriate to
101 // run a Task with |traits|.
102 // Note: ExecutionMode is verified inside TestTaskFactory.
VerifyTaskEnvironment(const TaskTraits & traits,bool use_resource_efficient_group)103 void VerifyTaskEnvironment(const TaskTraits& traits,
104 bool use_resource_efficient_group) {
105 const std::string thread_name(PlatformThread::GetName());
106 const bool is_single_threaded =
107 (thread_name.find("SingleThread") != std::string::npos);
108
109 const bool expect_background_thread_type =
110 TraitsSupportBackgroundThreadType(traits);
111
112 const bool expect_utility_thread_type =
113 !TraitsSupportBackgroundThreadType(traits) &&
114 TraitsSupportUtilityThreadType(traits) && use_resource_efficient_group;
115
116 EXPECT_EQ(expect_background_thread_type ? ThreadType::kBackground
117 : expect_utility_thread_type ? ThreadType::kUtility
118 : ThreadType::kDefault,
119 PlatformThread::GetCurrentThreadType());
120
121 if (traits.may_block())
122 internal::AssertBlockingAllowed();
123 else
124 internal::AssertBlockingDisallowedForTesting();
125
126 // Verify that the thread the task is running on is named as expected.
127 EXPECT_THAT(thread_name, ::testing::HasSubstr("ThreadPool"));
128
129 EXPECT_THAT(thread_name, ::testing::HasSubstr(
130 expect_background_thread_type ? "Background"
131 : expect_utility_thread_type ? "Utility"
132 : "Foreground"));
133
134 if (is_single_threaded) {
135 // SingleThread workers discriminate blocking/non-blocking tasks.
136 if (traits.may_block()) {
137 EXPECT_THAT(thread_name, ::testing::HasSubstr("Blocking"));
138 } else {
139 EXPECT_THAT(thread_name,
140 ::testing::Not(::testing::HasSubstr("Blocking")));
141 }
142 } else {
143 EXPECT_THAT(thread_name, ::testing::Not(::testing::HasSubstr("Blocking")));
144 }
145 }
146
VerifyTaskEnvironmentAndSignalEvent(const TaskTraits & traits,bool use_resource_efficient_group,TestWaitableEvent * event)147 void VerifyTaskEnvironmentAndSignalEvent(const TaskTraits& traits,
148 bool use_resource_efficient_group,
149 TestWaitableEvent* event) {
150 DCHECK(event);
151 VerifyTaskEnvironment(traits, use_resource_efficient_group);
152 event->Signal();
153 }
154
VerifyTimeAndTaskEnvironmentAndSignalEvent(const TaskTraits & traits,bool use_resource_efficient_group,TimeTicks expected_time,TestWaitableEvent * event)155 void VerifyTimeAndTaskEnvironmentAndSignalEvent(
156 const TaskTraits& traits,
157 bool use_resource_efficient_group,
158 TimeTicks expected_time,
159 TestWaitableEvent* event) {
160 DCHECK(event);
161 EXPECT_LE(expected_time, TimeTicks::Now());
162 VerifyTaskEnvironment(traits, use_resource_efficient_group);
163 event->Signal();
164 }
165
VerifyOrderAndTaskEnvironmentAndSignalEvent(const TaskTraits & traits,bool use_resource_efficient_group,TestWaitableEvent * expected_previous_event,TestWaitableEvent * event)166 void VerifyOrderAndTaskEnvironmentAndSignalEvent(
167 const TaskTraits& traits,
168 bool use_resource_efficient_group,
169 TestWaitableEvent* expected_previous_event,
170 TestWaitableEvent* event) {
171 DCHECK(event);
172 if (expected_previous_event)
173 EXPECT_TRUE(expected_previous_event->IsSignaled());
174 VerifyTaskEnvironment(traits, use_resource_efficient_group);
175 event->Signal();
176 }
177
CreateTaskRunnerAndExecutionMode(ThreadPoolImpl * thread_pool,const TaskTraits & traits,TaskSourceExecutionMode execution_mode,SingleThreadTaskRunnerThreadMode default_single_thread_task_runner_mode=SingleThreadTaskRunnerThreadMode::SHARED)178 scoped_refptr<TaskRunner> CreateTaskRunnerAndExecutionMode(
179 ThreadPoolImpl* thread_pool,
180 const TaskTraits& traits,
181 TaskSourceExecutionMode execution_mode,
182 SingleThreadTaskRunnerThreadMode default_single_thread_task_runner_mode =
183 SingleThreadTaskRunnerThreadMode::SHARED) {
184 switch (execution_mode) {
185 case TaskSourceExecutionMode::kParallel:
186 return thread_pool->CreateTaskRunner(traits);
187 case TaskSourceExecutionMode::kSequenced:
188 return thread_pool->CreateSequencedTaskRunner(traits);
189 case TaskSourceExecutionMode::kSingleThread: {
190 return thread_pool->CreateSingleThreadTaskRunner(
191 traits, default_single_thread_task_runner_mode);
192 }
193 case TaskSourceExecutionMode::kJob:
194 break;
195 }
196 ADD_FAILURE() << "Unknown ExecutionMode";
197 return nullptr;
198 }
199
200 class ThreadPostingTasks : public SimpleThread {
201 public:
202 // Creates a thread that posts Tasks to |thread_pool| with |traits| and
203 // |execution_mode|.
ThreadPostingTasks(ThreadPoolImpl * thread_pool,const TaskTraits & traits,bool use_resource_efficient_group,TaskSourceExecutionMode execution_mode)204 ThreadPostingTasks(ThreadPoolImpl* thread_pool,
205 const TaskTraits& traits,
206 bool use_resource_efficient_group,
207 TaskSourceExecutionMode execution_mode)
208 : SimpleThread("ThreadPostingTasks"),
209 traits_(traits),
210 use_resource_efficient_group_(use_resource_efficient_group),
211 factory_(CreateTaskRunnerAndExecutionMode(thread_pool,
212 traits,
213 execution_mode),
214 execution_mode) {}
215
216 ThreadPostingTasks(const ThreadPostingTasks&) = delete;
217 ThreadPostingTasks& operator=(const ThreadPostingTasks&) = delete;
218
WaitForAllTasksToRun()219 void WaitForAllTasksToRun() { factory_.WaitForAllTasksToRun(); }
220
221 private:
Run()222 void Run() override {
223 const size_t kNumTasksPerThread = 150;
224 for (size_t i = 0; i < kNumTasksPerThread; ++i) {
225 factory_.PostTask(test::TestTaskFactory::PostNestedTask::NO,
226 BindOnce(&VerifyTaskEnvironment, traits_,
227 use_resource_efficient_group_));
228 }
229 }
230
231 const TaskTraits traits_;
232 bool use_resource_efficient_group_;
233 test::TestTaskFactory factory_;
234 };
235
236 // Returns a vector with a TraitsExecutionModePair for each valid combination of
237 // {ExecutionMode, TaskPriority, ThreadPolicy, MayBlock()}.
GetTraitsExecutionModePairs()238 std::vector<TraitsExecutionModePair> GetTraitsExecutionModePairs() {
239 std::vector<TraitsExecutionModePair> params;
240
241 constexpr TaskSourceExecutionMode execution_modes[] = {
242 TaskSourceExecutionMode::kParallel, TaskSourceExecutionMode::kSequenced,
243 TaskSourceExecutionMode::kSingleThread};
244 constexpr ThreadPolicy thread_policies[] = {
245 ThreadPolicy::PREFER_BACKGROUND, ThreadPolicy::MUST_USE_FOREGROUND};
246
247 for (TaskSourceExecutionMode execution_mode : execution_modes) {
248 for (ThreadPolicy thread_policy : thread_policies) {
249 for (size_t priority_index = static_cast<size_t>(TaskPriority::LOWEST);
250 priority_index <= static_cast<size_t>(TaskPriority::HIGHEST);
251 ++priority_index) {
252 const TaskPriority priority = static_cast<TaskPriority>(priority_index);
253 params.push_back(
254 TraitsExecutionModePair({priority, thread_policy}, execution_mode));
255 params.push_back(TraitsExecutionModePair(
256 {priority, thread_policy, MayBlock()}, execution_mode));
257 }
258 }
259 }
260
261 return params;
262 }
263
264 // Returns a vector with enough TraitsExecutionModePairs to cover all valid
265 // combinations of task destination (background/foreground ThreadGroup,
266 // single-thread) and whether the task is affected by a BEST_EFFORT fence.
267 std::vector<TraitsExecutionModePair>
GetTraitsExecutionModePairsToCoverAllSchedulingOptions()268 GetTraitsExecutionModePairsToCoverAllSchedulingOptions() {
269 return {TraitsExecutionModePair({TaskPriority::BEST_EFFORT},
270 TaskSourceExecutionMode::kSequenced),
271 TraitsExecutionModePair({TaskPriority::USER_VISIBLE},
272 TaskSourceExecutionMode::kSequenced),
273 TraitsExecutionModePair({TaskPriority::USER_BLOCKING},
274 TaskSourceExecutionMode::kSequenced),
275 TraitsExecutionModePair({TaskPriority::BEST_EFFORT},
276 TaskSourceExecutionMode::kSingleThread),
277 TraitsExecutionModePair({TaskPriority::USER_VISIBLE},
278 TaskSourceExecutionMode::kSingleThread),
279 TraitsExecutionModePair({TaskPriority::USER_BLOCKING},
280 TaskSourceExecutionMode::kSingleThread)};
281 }
282
283 class ThreadPoolImplTestBase : public testing::Test {
284 public:
ThreadPoolImplTestBase()285 ThreadPoolImplTestBase()
286 : thread_pool_(std::make_unique<ThreadPoolImpl>("Test")),
287 service_thread_("ServiceThread") {
288 Thread::Options service_thread_options;
289 service_thread_options.message_pump_type = MessagePumpType::IO;
290 service_thread_.StartWithOptions(std::move(service_thread_options));
291 }
292
293 ThreadPoolImplTestBase(const ThreadPoolImplTestBase&) = delete;
294 ThreadPoolImplTestBase& operator=(const ThreadPoolImplTestBase&) = delete;
295
296 virtual bool GetUseResourceEfficientThreadGroup() const = 0;
297 virtual bool GetUseNewJobImplementation() const = 0;
298
set_worker_thread_observer(std::unique_ptr<WorkerThreadObserver> worker_thread_observer)299 void set_worker_thread_observer(
300 std::unique_ptr<WorkerThreadObserver> worker_thread_observer) {
301 worker_thread_observer_ = std::move(worker_thread_observer);
302 }
303
StartThreadPool(size_t max_num_foreground_threads=kMaxNumForegroundThreads,size_t max_num_utility_threads=kMaxNumUtilityThreads,TimeDelta reclaim_time=Seconds (30))304 void StartThreadPool(
305 size_t max_num_foreground_threads = kMaxNumForegroundThreads,
306 size_t max_num_utility_threads = kMaxNumUtilityThreads,
307 TimeDelta reclaim_time = Seconds(30)) {
308 SetupFeatures();
309
310 ThreadPoolInstance::InitParams init_params(max_num_foreground_threads,
311 max_num_utility_threads);
312 init_params.suggested_reclaim_time = reclaim_time;
313
314 thread_pool_->Start(init_params, worker_thread_observer_.get());
315 }
316
TearDown()317 void TearDown() override {
318 if (did_tear_down_)
319 return;
320
321 if (thread_pool_) {
322 thread_pool_->FlushForTesting();
323 thread_pool_->JoinForTesting();
324 thread_pool_.reset();
325 }
326 did_tear_down_ = true;
327 }
328
329 std::unique_ptr<ThreadPoolImpl> thread_pool_;
330 Thread service_thread_;
331
332 private:
SetupFeatures()333 void SetupFeatures() {
334 std::vector<base::test::FeatureRef> enabled_features;
335 std::vector<base::test::FeatureRef> disabled_features;
336
337 if (GetUseResourceEfficientThreadGroup()) {
338 enabled_features.push_back(kUseUtilityThreadGroup);
339 } else {
340 disabled_features.push_back(kUseUtilityThreadGroup);
341 }
342
343 if (GetUseNewJobImplementation()) {
344 enabled_features.push_back(kUseNewJobImplementation);
345 } else {
346 disabled_features.push_back(kUseNewJobImplementation);
347 }
348
349 feature_list_.InitWithFeatures(enabled_features, disabled_features);
350 }
351
352 base::test::ScopedFeatureList feature_list_;
353 std::unique_ptr<WorkerThreadObserver> worker_thread_observer_;
354 bool did_tear_down_ = false;
355 };
356
357 class ThreadPoolImplTest
358 : public ThreadPoolImplTestBase,
359 public testing::WithParamInterface<
360 std::pair<bool, /* use_resource_efficient_thread_group */
361 bool /* use_new_job_implementation */>> {
362 public:
GetUseResourceEfficientThreadGroup() const363 bool GetUseResourceEfficientThreadGroup() const override {
364 return GetParam().first;
365 }
366
GetUseNewJobImplementation() const367 bool GetUseNewJobImplementation() const override { return GetParam().second; }
368 };
369
370 // Tests run for enough traits and execution mode combinations to cover all
371 // valid combinations of task destination (background/foreground ThreadGroup,
372 // single-thread) and whether the task is affected by a BEST_EFFORT fence.
373 class ThreadPoolImplTest_CoverAllSchedulingOptions
374 : public ThreadPoolImplTestBase,
375 public testing::WithParamInterface<
376 std::tuple<bool /* use_resource_efficient_thread_group */,
377 TraitsExecutionModePair>> {
378 public:
379 ThreadPoolImplTest_CoverAllSchedulingOptions() = default;
380 ThreadPoolImplTest_CoverAllSchedulingOptions(
381 const ThreadPoolImplTest_CoverAllSchedulingOptions&) = delete;
382 ThreadPoolImplTest_CoverAllSchedulingOptions& operator=(
383 const ThreadPoolImplTest_CoverAllSchedulingOptions&) = delete;
384
GetUseResourceEfficientThreadGroup() const385 bool GetUseResourceEfficientThreadGroup() const override {
386 return std::get<0>(GetParam());
387 }
GetUseNewJobImplementation() const388 bool GetUseNewJobImplementation() const override { return true; }
GetTraits() const389 TaskTraits GetTraits() const { return std::get<1>(GetParam()).traits; }
GetExecutionMode() const390 TaskSourceExecutionMode GetExecutionMode() const {
391 return std::get<1>(GetParam()).execution_mode;
392 }
393 };
394
395 } // namespace
396
397 // Verifies that a Task posted via PostDelayedTask with parameterized TaskTraits
398 // and no delay runs on a thread with the expected priority and I/O
399 // restrictions. The ExecutionMode parameter is ignored by this test.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostDelayedTaskNoDelay)400 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, PostDelayedTaskNoDelay) {
401 StartThreadPool();
402 TestWaitableEvent task_ran;
403 thread_pool_->PostDelayedTask(
404 FROM_HERE, GetTraits(),
405 BindOnce(&VerifyTaskEnvironmentAndSignalEvent, GetTraits(),
406 GetUseResourceEfficientThreadGroup(), Unretained(&task_ran)),
407 TimeDelta());
408 task_ran.Wait();
409 }
410
411 // Verifies that a Task posted via PostDelayedTask with parameterized
412 // TaskTraits and a non-zero delay runs on a thread with the expected priority
413 // and I/O restrictions after the delay expires. The ExecutionMode parameter is
414 // ignored by this test.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostDelayedTaskWithDelay)415 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, PostDelayedTaskWithDelay) {
416 StartThreadPool();
417 TestWaitableEvent task_ran;
418 thread_pool_->PostDelayedTask(
419 FROM_HERE, GetTraits(),
420 BindOnce(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetTraits(),
421 GetUseResourceEfficientThreadGroup(),
422 TimeTicks::Now() + TestTimeouts::tiny_timeout(),
423 Unretained(&task_ran)),
424 TestTimeouts::tiny_timeout());
425 task_ran.Wait();
426 }
427
428 namespace {
429
CreateSequencedTaskRunnerAndExecutionMode(ThreadPoolImpl * thread_pool,const TaskTraits & traits,TaskSourceExecutionMode execution_mode,SingleThreadTaskRunnerThreadMode default_single_thread_task_runner_mode=SingleThreadTaskRunnerThreadMode::SHARED)430 scoped_refptr<SequencedTaskRunner> CreateSequencedTaskRunnerAndExecutionMode(
431 ThreadPoolImpl* thread_pool,
432 const TaskTraits& traits,
433 TaskSourceExecutionMode execution_mode,
434 SingleThreadTaskRunnerThreadMode default_single_thread_task_runner_mode =
435 SingleThreadTaskRunnerThreadMode::SHARED) {
436 switch (execution_mode) {
437 case TaskSourceExecutionMode::kSequenced:
438 return thread_pool->CreateSequencedTaskRunner(traits);
439 case TaskSourceExecutionMode::kSingleThread: {
440 return thread_pool->CreateSingleThreadTaskRunner(
441 traits, default_single_thread_task_runner_mode);
442 }
443 case TaskSourceExecutionMode::kParallel:
444 case TaskSourceExecutionMode::kJob:
445 ADD_FAILURE() << "Tests below don't cover these modes";
446 return nullptr;
447 }
448 ADD_FAILURE() << "Unknown ExecutionMode";
449 return nullptr;
450 }
451
452 } // namespace
453
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostDelayedTaskAtViaTaskRunner)454 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,
455 PostDelayedTaskAtViaTaskRunner) {
456 StartThreadPool();
457 TestWaitableEvent task_ran;
458 // Only runs for kSequenced and kSingleThread.
459 auto handle =
460 CreateSequencedTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
461 GetExecutionMode())
462 ->PostCancelableDelayedTaskAt(
463 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
464 BindOnce(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetTraits(),
465 GetUseResourceEfficientThreadGroup(),
466 TimeTicks::Now() + TestTimeouts::tiny_timeout(),
467 Unretained(&task_ran)),
468 TimeTicks::Now() + TestTimeouts::tiny_timeout(),
469 subtle::DelayPolicy::kFlexibleNoSooner);
470 task_ran.Wait();
471 }
472
473 // Verifies that Tasks posted via a TaskRunner with parameterized TaskTraits and
474 // ExecutionMode run on a thread with the expected priority and I/O restrictions
475 // and respect the characteristics of their ExecutionMode.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostTasksViaTaskRunner)476 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, PostTasksViaTaskRunner) {
477 StartThreadPool();
478 test::TestTaskFactory factory(
479 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
480 GetExecutionMode()),
481 GetExecutionMode());
482
483 const size_t kNumTasksPerTest = 150;
484 for (size_t i = 0; i < kNumTasksPerTest; ++i) {
485 factory.PostTask(test::TestTaskFactory::PostNestedTask::NO,
486 BindOnce(&VerifyTaskEnvironment, GetTraits(),
487 GetUseResourceEfficientThreadGroup()));
488 }
489
490 factory.WaitForAllTasksToRun();
491 }
492
493 // Verifies that a task posted via PostDelayedTask without a delay doesn't run
494 // before Start() is called.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostDelayedTaskNoDelayBeforeStart)495 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,
496 PostDelayedTaskNoDelayBeforeStart) {
497 TestWaitableEvent task_running;
498 thread_pool_->PostDelayedTask(
499 FROM_HERE, GetTraits(),
500 BindOnce(&VerifyTaskEnvironmentAndSignalEvent, GetTraits(),
501 GetUseResourceEfficientThreadGroup(), Unretained(&task_running)),
502 TimeDelta());
503
504 // Wait a little bit to make sure that the task doesn't run before Start().
505 // Note: This test won't catch a case where the task runs just after the check
506 // and before Start(). However, we expect the test to be flaky if the tested
507 // code allows that to happen.
508 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
509 EXPECT_FALSE(task_running.IsSignaled());
510
511 StartThreadPool();
512 task_running.Wait();
513 }
514
515 // Verifies that a task posted via PostDelayedTask with a delay doesn't run
516 // before Start() is called.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostDelayedTaskWithDelayBeforeStart)517 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,
518 PostDelayedTaskWithDelayBeforeStart) {
519 TestWaitableEvent task_running;
520 thread_pool_->PostDelayedTask(
521 FROM_HERE, GetTraits(),
522 BindOnce(&VerifyTimeAndTaskEnvironmentAndSignalEvent, GetTraits(),
523 GetUseResourceEfficientThreadGroup(),
524 TimeTicks::Now() + TestTimeouts::tiny_timeout(),
525 Unretained(&task_running)),
526 TestTimeouts::tiny_timeout());
527
528 // Wait a little bit to make sure that the task doesn't run before Start().
529 // Note: This test won't catch a case where the task runs just after the check
530 // and before Start(). However, we expect the test to be flaky if the tested
531 // code allows that to happen.
532 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
533 EXPECT_FALSE(task_running.IsSignaled());
534
535 StartThreadPool();
536 task_running.Wait();
537 }
538
539 // Verifies that a task posted via a TaskRunner doesn't run before Start() is
540 // called.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostTaskViaTaskRunnerBeforeStart)541 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,
542 PostTaskViaTaskRunnerBeforeStart) {
543 bool use_resource_efficient_thread_group =
544 GetUseResourceEfficientThreadGroup();
545 // The worker_thread of SingleThreadTaskRunner is selected before
546 // kUseUtilityThreadGroup feature is set up at StartThreadPool().
547 if (GetExecutionMode() == TaskSourceExecutionMode::kSingleThread) {
548 use_resource_efficient_thread_group = false;
549 }
550 TestWaitableEvent task_running;
551 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
552 GetExecutionMode())
553 ->PostTask(FROM_HERE,
554 BindOnce(&VerifyTaskEnvironmentAndSignalEvent, GetTraits(),
555 use_resource_efficient_thread_group,
556 Unretained(&task_running)));
557
558 // Wait a little bit to make sure that the task doesn't run before Start().
559 // Note: This test won't catch a case where the task runs just after the check
560 // and before Start(). However, we expect the test to be flaky if the tested
561 // code allows that to happen.
562 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
563 EXPECT_FALSE(task_running.IsSignaled());
564
565 StartThreadPool();
566
567 // This should not hang if the task runs after Start().
568 task_running.Wait();
569 }
570
571 // Verify that posting tasks after the thread pool was destroyed fails but
572 // doesn't crash.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,PostTaskAfterDestroy)573 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, PostTaskAfterDestroy) {
574 StartThreadPool();
575
576 auto task_runner = CreateTaskRunnerAndExecutionMode(
577 thread_pool_.get(), GetTraits(), GetExecutionMode());
578 EXPECT_TRUE(task_runner->PostTask(FROM_HERE, DoNothing()));
579 thread_pool_->JoinForTesting();
580 thread_pool_.reset();
581
582 EXPECT_FALSE(
583 task_runner->PostTask(FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)));
584 }
585
586 // Verifies that FlushAsyncForTesting() calls back correctly for all trait and
587 // execution mode pairs.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,FlushAsyncForTestingSimple)588 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,
589 FlushAsyncForTestingSimple) {
590 StartThreadPool();
591
592 TestWaitableEvent unblock_task;
593 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
594 GetExecutionMode(),
595 SingleThreadTaskRunnerThreadMode::DEDICATED)
596 ->PostTask(FROM_HERE,
597 BindOnce(&TestWaitableEvent::Wait, Unretained(&unblock_task)));
598
599 TestWaitableEvent flush_event;
600 thread_pool_->FlushAsyncForTesting(
601 BindOnce(&TestWaitableEvent::Signal, Unretained(&flush_event)));
602 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
603 EXPECT_FALSE(flush_event.IsSignaled());
604
605 unblock_task.Signal();
606
607 flush_event.Wait();
608 }
609
610 // Verifies that BEST_EFFORT tasks don't run when the
611 // --disable-best-effort-tasks command-line switch is specified.
612 //
613 // Not using the same fixture as other tests because we want to append a command
614 // line switch before creating the pool.
TEST(ThreadPoolImplTest_Switch,DisableBestEffortTasksSwitch)615 TEST(ThreadPoolImplTest_Switch, DisableBestEffortTasksSwitch) {
616 CommandLine::ForCurrentProcess()->AppendSwitch(
617 switches::kDisableBestEffortTasks);
618
619 ThreadPoolImpl thread_pool("Test");
620 ThreadPoolInstance::InitParams init_params(kMaxNumForegroundThreads,
621 kMaxNumUtilityThreads);
622 thread_pool.Start(init_params, nullptr);
623
624 AtomicFlag best_effort_can_run;
625 TestWaitableEvent best_effort_did_run;
626 thread_pool.PostDelayedTask(
627 FROM_HERE,
628 {TaskPriority::BEST_EFFORT, TaskShutdownBehavior::BLOCK_SHUTDOWN},
629 BindLambdaForTesting([&]() {
630 EXPECT_TRUE(best_effort_can_run.IsSet());
631 best_effort_did_run.Signal();
632 }),
633 TimeDelta());
634
635 TestWaitableEvent user_blocking_did_run;
636 thread_pool.PostDelayedTask(
637 FROM_HERE, {TaskPriority::USER_BLOCKING},
638 BindLambdaForTesting([&]() { user_blocking_did_run.Signal(); }),
639 TimeDelta());
640
641 // The USER_BLOCKING task should run.
642 user_blocking_did_run.Wait();
643
644 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
645
646 // The BEST_EFFORT task should not run when a BEST_EFFORT fence is deleted.
647 thread_pool.BeginBestEffortFence();
648 thread_pool.EndBestEffortFence();
649
650 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
651
652 // The BEST_EFFORT task should only run during shutdown.
653 best_effort_can_run.Set();
654 thread_pool.Shutdown();
655 EXPECT_TRUE(best_effort_did_run.IsSignaled());
656 thread_pool.JoinForTesting();
657 }
658
659 // Verifies that tasks only run when allowed by fences.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,Fence)660 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, Fence) {
661 StartThreadPool();
662
663 AtomicFlag can_run;
664 TestWaitableEvent did_run;
665 thread_pool_->BeginFence();
666
667 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
668 GetExecutionMode())
669 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
670 EXPECT_TRUE(can_run.IsSet());
671 did_run.Signal();
672 }));
673
674 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
675
676 can_run.Set();
677 thread_pool_->EndFence();
678 did_run.Wait();
679 }
680
681 // Verifies that multiple fences can exist at the same time.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,MultipleFences)682 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, MultipleFences) {
683 StartThreadPool();
684
685 AtomicFlag can_run;
686 TestWaitableEvent did_run;
687 thread_pool_->BeginFence();
688 thread_pool_->BeginFence();
689
690 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
691 GetExecutionMode())
692 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
693 EXPECT_TRUE(can_run.IsSet());
694 did_run.Signal();
695 }));
696
697 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
698
699 thread_pool_->EndFence();
700 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
701
702 // The task can only run when both fences are removed.
703 can_run.Set();
704 thread_pool_->EndFence();
705
706 did_run.Wait();
707 }
708
709 // Verifies that a call to BeginFence() before Start() is honored.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,FenceBeforeStart)710 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, FenceBeforeStart) {
711 thread_pool_->BeginFence();
712 StartThreadPool();
713
714 AtomicFlag can_run;
715 TestWaitableEvent did_run;
716
717 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
718 GetExecutionMode())
719 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
720 EXPECT_TRUE(can_run.IsSet());
721 did_run.Signal();
722 }));
723
724 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
725
726 can_run.Set();
727 thread_pool_->EndFence();
728 did_run.Wait();
729 }
730
731 // Verifies that tasks only run when allowed by BEST_EFFORT fences.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,BestEffortFence)732 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, BestEffortFence) {
733 StartThreadPool();
734
735 AtomicFlag can_run;
736 TestWaitableEvent did_run;
737 thread_pool_->BeginBestEffortFence();
738
739 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
740 GetExecutionMode())
741 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
742 if (GetTraits().priority() == TaskPriority::BEST_EFFORT)
743 EXPECT_TRUE(can_run.IsSet());
744 did_run.Signal();
745 }));
746
747 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
748
749 can_run.Set();
750 thread_pool_->EndBestEffortFence();
751 did_run.Wait();
752 }
753
754 // Verifies that multiple BEST_EFFORT fences can exist at the same time.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,MultipleBestEffortFences)755 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, MultipleBestEffortFences) {
756 StartThreadPool();
757
758 AtomicFlag can_run;
759 TestWaitableEvent did_run;
760 thread_pool_->BeginBestEffortFence();
761 thread_pool_->BeginBestEffortFence();
762
763 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
764 GetExecutionMode())
765 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
766 if (GetTraits().priority() == TaskPriority::BEST_EFFORT)
767 EXPECT_TRUE(can_run.IsSet());
768 did_run.Signal();
769 }));
770
771 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
772
773 thread_pool_->EndBestEffortFence();
774 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
775
776 // The task can only run when both fences are removed.
777 can_run.Set();
778 thread_pool_->EndBestEffortFence();
779
780 did_run.Wait();
781 }
782
783 // Verifies that a call to BeginBestEffortFence() before Start() is honored.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,BestEffortFenceBeforeStart)784 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,
785 BestEffortFenceBeforeStart) {
786 thread_pool_->BeginBestEffortFence();
787 StartThreadPool();
788
789 AtomicFlag can_run;
790 TestWaitableEvent did_run;
791
792 CreateTaskRunnerAndExecutionMode(thread_pool_.get(), GetTraits(),
793 GetExecutionMode())
794 ->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
795 if (GetTraits().priority() == TaskPriority::BEST_EFFORT)
796 EXPECT_TRUE(can_run.IsSet());
797 did_run.Signal();
798 }));
799
800 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
801
802 can_run.Set();
803 thread_pool_->EndBestEffortFence();
804 did_run.Wait();
805 }
806
807 // Spawns threads that simultaneously post Tasks to TaskRunners with various
808 // TaskTraits and ExecutionModes. Verifies that each Task runs on a thread with
809 // the expected priority and I/O restrictions and respects the characteristics
810 // of its ExecutionMode.
TEST_P(ThreadPoolImplTest,MultipleTraitsExecutionModePair)811 TEST_P(ThreadPoolImplTest, MultipleTraitsExecutionModePair) {
812 StartThreadPool();
813 std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks;
814 for (const auto& test_params : GetTraitsExecutionModePairs()) {
815 threads_posting_tasks.push_back(std::make_unique<ThreadPostingTasks>(
816 thread_pool_.get(), test_params.traits,
817 GetUseResourceEfficientThreadGroup(), test_params.execution_mode));
818 threads_posting_tasks.back()->Start();
819 }
820
821 for (const auto& thread : threads_posting_tasks) {
822 thread->WaitForAllTasksToRun();
823 thread->Join();
824 }
825 }
826
TEST_P(ThreadPoolImplTest,GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated)827 TEST_P(ThreadPoolImplTest,
828 GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated) {
829 StartThreadPool();
830
831 // GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated() does not support
832 // TaskPriority::BEST_EFFORT.
833 GTEST_FLAG_SET(death_test_style, "threadsafe");
834 EXPECT_DCHECK_DEATH({
835 thread_pool_->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
836 {TaskPriority::BEST_EFFORT});
837 });
838 EXPECT_DCHECK_DEATH({
839 thread_pool_->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
840 {MayBlock(), TaskPriority::BEST_EFFORT});
841 });
842
843 EXPECT_EQ(GetUseResourceEfficientThreadGroup() &&
844 CanUseUtilityThreadTypeForWorkerThread()
845 ? kMaxNumUtilityThreads
846 : kMaxNumForegroundThreads,
847 thread_pool_->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
848 {TaskPriority::USER_VISIBLE}));
849 EXPECT_EQ(GetUseResourceEfficientThreadGroup() &&
850 CanUseUtilityThreadTypeForWorkerThread()
851 ? kMaxNumUtilityThreads
852 : kMaxNumForegroundThreads,
853 thread_pool_->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
854 {MayBlock(), TaskPriority::USER_VISIBLE}));
855 EXPECT_EQ(kMaxNumForegroundThreads,
856 thread_pool_->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
857 {TaskPriority::USER_BLOCKING}));
858 EXPECT_EQ(kMaxNumForegroundThreads,
859 thread_pool_->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
860 {MayBlock(), TaskPriority::USER_BLOCKING}));
861 }
862
863 // Verify that the RunsTasksInCurrentSequence() method of a SequencedTaskRunner
864 // returns false when called from a task that isn't part of the sequence.
TEST_P(ThreadPoolImplTest,SequencedRunsTasksInCurrentSequence)865 TEST_P(ThreadPoolImplTest, SequencedRunsTasksInCurrentSequence) {
866 StartThreadPool();
867 auto single_thread_task_runner = thread_pool_->CreateSingleThreadTaskRunner(
868 {}, SingleThreadTaskRunnerThreadMode::SHARED);
869 auto sequenced_task_runner = thread_pool_->CreateSequencedTaskRunner({});
870
871 TestWaitableEvent task_ran;
872 single_thread_task_runner->PostTask(
873 FROM_HERE,
874 BindOnce(
875 [](scoped_refptr<SequencedTaskRunner> sequenced_task_runner,
876 TestWaitableEvent* task_ran) {
877 EXPECT_FALSE(sequenced_task_runner->RunsTasksInCurrentSequence());
878 task_ran->Signal();
879 },
880 sequenced_task_runner, Unretained(&task_ran)));
881 task_ran.Wait();
882 }
883
884 // Verify that the RunsTasksInCurrentSequence() method of a
885 // SingleThreadTaskRunner returns false when called from a task that isn't part
886 // of the sequence.
TEST_P(ThreadPoolImplTest,SingleThreadRunsTasksInCurrentSequence)887 TEST_P(ThreadPoolImplTest, SingleThreadRunsTasksInCurrentSequence) {
888 StartThreadPool();
889 auto sequenced_task_runner = thread_pool_->CreateSequencedTaskRunner({});
890 auto single_thread_task_runner = thread_pool_->CreateSingleThreadTaskRunner(
891 {}, SingleThreadTaskRunnerThreadMode::SHARED);
892
893 TestWaitableEvent task_ran;
894 sequenced_task_runner->PostTask(
895 FROM_HERE,
896 BindOnce(
897 [](scoped_refptr<SingleThreadTaskRunner> single_thread_task_runner,
898 TestWaitableEvent* task_ran) {
899 EXPECT_FALSE(
900 single_thread_task_runner->RunsTasksInCurrentSequence());
901 task_ran->Signal();
902 },
903 single_thread_task_runner, Unretained(&task_ran)));
904 task_ran.Wait();
905 }
906
907 #if BUILDFLAG(IS_WIN)
TEST_P(ThreadPoolImplTest,COMSTATaskRunnersRunWithCOMSTA)908 TEST_P(ThreadPoolImplTest, COMSTATaskRunnersRunWithCOMSTA) {
909 StartThreadPool();
910 auto com_sta_task_runner = thread_pool_->CreateCOMSTATaskRunner(
911 {}, SingleThreadTaskRunnerThreadMode::SHARED);
912
913 TestWaitableEvent task_ran;
914 com_sta_task_runner->PostTask(
915 FROM_HERE, BindOnce(
916 [](TestWaitableEvent* task_ran) {
917 win::AssertComApartmentType(win::ComApartmentType::STA);
918 task_ran->Signal();
919 },
920 Unretained(&task_ran)));
921 task_ran.Wait();
922 }
923 #endif // BUILDFLAG(IS_WIN)
924
TEST_P(ThreadPoolImplTest,DelayedTasksNotRunAfterShutdown)925 TEST_P(ThreadPoolImplTest, DelayedTasksNotRunAfterShutdown) {
926 StartThreadPool();
927 // As with delayed tasks in general, this is racy. If the task does happen to
928 // run after Shutdown within the timeout, it will fail this test.
929 //
930 // The timeout should be set sufficiently long enough to ensure that the
931 // delayed task did not run. 2x is generally good enough.
932 //
933 // A non-racy way to do this would be to post two sequenced tasks:
934 // 1) Regular Post Task: A WaitableEvent.Wait
935 // 2) Delayed Task: ADD_FAILURE()
936 // and signalling the WaitableEvent after Shutdown() on a different thread
937 // since Shutdown() will block. However, the cost of managing this extra
938 // thread was deemed to be too great for the unlikely race.
939 thread_pool_->PostDelayedTask(FROM_HERE, {},
940 BindOnce([]() { ADD_FAILURE(); }),
941 TestTimeouts::tiny_timeout());
942 thread_pool_->Shutdown();
943 PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 2);
944 }
945
946 #if BUILDFLAG(IS_POSIX)
947
TEST_P(ThreadPoolImplTest,FileDescriptorWatcherNoOpsAfterShutdown)948 TEST_P(ThreadPoolImplTest, FileDescriptorWatcherNoOpsAfterShutdown) {
949 StartThreadPool();
950
951 int pipes[2];
952 ASSERT_EQ(0, pipe(pipes));
953
954 scoped_refptr<TaskRunner> blocking_task_runner =
955 thread_pool_->CreateSequencedTaskRunner(
956 {TaskShutdownBehavior::BLOCK_SHUTDOWN});
957 blocking_task_runner->PostTask(
958 FROM_HERE,
959 BindOnce(
960 [](int read_fd) {
961 std::unique_ptr<FileDescriptorWatcher::Controller> controller =
962 FileDescriptorWatcher::WatchReadable(
963 read_fd, BindRepeating([]() { NOTREACHED(); }));
964
965 // This test is for components that intentionally leak their
966 // watchers at shutdown. We can't clean |controller| up because its
967 // destructor will assert that it's being called from the correct
968 // sequence. After the thread pool is shutdown, it is not
969 // possible to run tasks on this sequence.
970 //
971 // Note: Do not inline the controller.release() call into the
972 // ANNOTATE_LEAKING_OBJECT_PTR as the annotation is removed
973 // by the preprocessor in non-LEAK_SANITIZER builds,
974 // effectively breaking this test.
975 ANNOTATE_LEAKING_OBJECT_PTR(controller.get());
976 controller.release();
977 },
978 pipes[0]));
979
980 thread_pool_->Shutdown();
981
982 constexpr char kByte = '!';
983 ASSERT_TRUE(WriteFileDescriptor(pipes[1], as_bytes(make_span(&kByte, 1u))));
984
985 // Give a chance for the file watcher to fire before closing the handles.
986 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
987
988 EXPECT_EQ(0, IGNORE_EINTR(close(pipes[0])));
989 EXPECT_EQ(0, IGNORE_EINTR(close(pipes[1])));
990 }
991 #endif // BUILDFLAG(IS_POSIX)
992
993 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
994
995 // Verify that FileDescriptorWatcher::WatchReadable() can be called from task
996 // running on a task_runner with GetExecutionMode() without a crash.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,FileDescriptorWatcher)997 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, FileDescriptorWatcher) {
998 StartThreadPool();
999
1000 int fds[2];
1001 ASSERT_EQ(0, pipe(fds));
1002
1003 auto task_runner = CreateTaskRunnerAndExecutionMode(
1004 thread_pool_.get(), GetTraits(), GetExecutionMode());
1005
1006 EXPECT_TRUE(task_runner->PostTask(
1007 FROM_HERE, BindOnce(IgnoreResult(&FileDescriptorWatcher::WatchReadable),
1008 fds[0], DoNothing())));
1009
1010 thread_pool_->FlushForTesting();
1011
1012 EXPECT_EQ(0, IGNORE_EINTR(close(fds[0])));
1013 EXPECT_EQ(0, IGNORE_EINTR(close(fds[1])));
1014 }
1015
1016 #endif
1017
1018 // Verify that tasks posted on the same sequence access the same values on
1019 // SequenceLocalStorage, and tasks on different sequences see different values.
TEST_P(ThreadPoolImplTest,SequenceLocalStorage)1020 TEST_P(ThreadPoolImplTest, SequenceLocalStorage) {
1021 StartThreadPool();
1022
1023 SequenceLocalStorageSlot<int> slot;
1024 auto sequenced_task_runner1 = thread_pool_->CreateSequencedTaskRunner({});
1025 auto sequenced_task_runner2 = thread_pool_->CreateSequencedTaskRunner({});
1026
1027 sequenced_task_runner1->PostTask(
1028 FROM_HERE,
1029 BindOnce([](SequenceLocalStorageSlot<int>* slot) { slot->emplace(11); },
1030 &slot));
1031
1032 sequenced_task_runner1->PostTask(
1033 FROM_HERE, BindOnce(
1034 [](SequenceLocalStorageSlot<int>* slot) {
1035 EXPECT_EQ(slot->GetOrCreateValue(), 11);
1036 },
1037 &slot));
1038
1039 sequenced_task_runner2->PostTask(
1040 FROM_HERE, BindOnce(
1041 [](SequenceLocalStorageSlot<int>* slot) {
1042 EXPECT_NE(slot->GetOrCreateValue(), 11);
1043 },
1044 &slot));
1045
1046 thread_pool_->FlushForTesting();
1047 }
1048
TEST_P(ThreadPoolImplTest,FlushAsyncNoTasks)1049 TEST_P(ThreadPoolImplTest, FlushAsyncNoTasks) {
1050 StartThreadPool();
1051 bool called_back = false;
1052 thread_pool_->FlushAsyncForTesting(
1053 BindOnce([](bool* called_back) { *called_back = true; },
1054 Unretained(&called_back)));
1055 EXPECT_TRUE(called_back);
1056 }
1057
1058 namespace {
1059
1060 // Verifies that all strings passed as argument are found on the current stack.
1061 // Ignores failures if this configuration doesn't have symbols.
VerifyHasStringsOnStack(const std::string & pool_str,const std::string & shutdown_behavior_str)1062 void VerifyHasStringsOnStack(const std::string& pool_str,
1063 const std::string& shutdown_behavior_str) {
1064 const std::string stack = debug::StackTrace().ToString();
1065 SCOPED_TRACE(stack);
1066 const bool stack_has_symbols =
1067 stack.find("WorkerThread") != std::string::npos;
1068 if (!stack_has_symbols)
1069 return;
1070
1071 EXPECT_THAT(stack, ::testing::HasSubstr(pool_str));
1072 EXPECT_THAT(stack, ::testing::HasSubstr(shutdown_behavior_str));
1073 }
1074
1075 } // namespace
1076
1077 #if BUILDFLAG(IS_POSIX)
1078 // Many POSIX bots flakily crash on |debug::StackTrace().ToString()|,
1079 // https://crbug.com/840429.
1080 #define MAYBE_IdentifiableStacks DISABLED_IdentifiableStacks
1081 #elif BUILDFLAG(IS_WIN) && \
1082 (defined(ADDRESS_SANITIZER) || BUILDFLAG(CFI_CAST_CHECK))
1083 // Hangs on WinASan and WinCFI (grabbing StackTrace() too slow?),
1084 // https://crbug.com/845010#c7.
1085 #define MAYBE_IdentifiableStacks DISABLED_IdentifiableStacks
1086 #else
1087 #define MAYBE_IdentifiableStacks IdentifiableStacks
1088 #endif
1089
1090 // Integration test that verifies that workers have a frame on their stacks
1091 // which easily identifies the type of worker and shutdown behavior (useful to
1092 // diagnose issues from logs without memory dumps).
TEST_P(ThreadPoolImplTest,MAYBE_IdentifiableStacks)1093 TEST_P(ThreadPoolImplTest, MAYBE_IdentifiableStacks) {
1094 StartThreadPool();
1095
1096 // Shutdown behaviors and expected stack frames.
1097 constexpr std::pair<TaskShutdownBehavior, const char*> shutdown_behaviors[] =
1098 {{TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, "RunContinueOnShutdown"},
1099 {TaskShutdownBehavior::SKIP_ON_SHUTDOWN, "RunSkipOnShutdown"},
1100 {TaskShutdownBehavior::BLOCK_SHUTDOWN, "RunBlockShutdown"}};
1101
1102 for (const auto& shutdown_behavior : shutdown_behaviors) {
1103 const TaskTraits traits = {shutdown_behavior.first};
1104 const TaskTraits best_effort_traits = {shutdown_behavior.first,
1105 TaskPriority::BEST_EFFORT};
1106
1107 thread_pool_->CreateSequencedTaskRunner(traits)->PostTask(
1108 FROM_HERE, BindOnce(&VerifyHasStringsOnStack, "RunPooledWorker",
1109 shutdown_behavior.second));
1110 thread_pool_->CreateSequencedTaskRunner(best_effort_traits)
1111 ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringsOnStack,
1112 "RunBackgroundPooledWorker",
1113 shutdown_behavior.second));
1114
1115 thread_pool_
1116 ->CreateSingleThreadTaskRunner(traits,
1117 SingleThreadTaskRunnerThreadMode::SHARED)
1118 ->PostTask(FROM_HERE,
1119 BindOnce(&VerifyHasStringsOnStack, "RunSharedWorker",
1120 shutdown_behavior.second));
1121 thread_pool_
1122 ->CreateSingleThreadTaskRunner(best_effort_traits,
1123 SingleThreadTaskRunnerThreadMode::SHARED)
1124 ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringsOnStack,
1125 "RunBackgroundSharedWorker",
1126 shutdown_behavior.second));
1127
1128 thread_pool_
1129 ->CreateSingleThreadTaskRunner(
1130 traits, SingleThreadTaskRunnerThreadMode::DEDICATED)
1131 ->PostTask(FROM_HERE,
1132 BindOnce(&VerifyHasStringsOnStack, "RunDedicatedWorker",
1133 shutdown_behavior.second));
1134 thread_pool_
1135 ->CreateSingleThreadTaskRunner(
1136 best_effort_traits, SingleThreadTaskRunnerThreadMode::DEDICATED)
1137 ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringsOnStack,
1138 "RunBackgroundDedicatedWorker",
1139 shutdown_behavior.second));
1140
1141 #if BUILDFLAG(IS_WIN)
1142 thread_pool_
1143 ->CreateCOMSTATaskRunner(traits,
1144 SingleThreadTaskRunnerThreadMode::SHARED)
1145 ->PostTask(FROM_HERE,
1146 BindOnce(&VerifyHasStringsOnStack, "RunSharedCOMWorker",
1147 shutdown_behavior.second));
1148 thread_pool_
1149 ->CreateCOMSTATaskRunner(best_effort_traits,
1150 SingleThreadTaskRunnerThreadMode::SHARED)
1151 ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringsOnStack,
1152 "RunBackgroundSharedCOMWorker",
1153 shutdown_behavior.second));
1154
1155 thread_pool_
1156 ->CreateCOMSTATaskRunner(traits,
1157 SingleThreadTaskRunnerThreadMode::DEDICATED)
1158 ->PostTask(FROM_HERE,
1159 BindOnce(&VerifyHasStringsOnStack, "RunDedicatedCOMWorker",
1160 shutdown_behavior.second));
1161 thread_pool_
1162 ->CreateCOMSTATaskRunner(best_effort_traits,
1163 SingleThreadTaskRunnerThreadMode::DEDICATED)
1164 ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringsOnStack,
1165 "RunBackgroundDedicatedCOMWorker",
1166 shutdown_behavior.second));
1167 #endif // BUILDFLAG(IS_WIN)
1168 }
1169
1170 thread_pool_->FlushForTesting();
1171 }
1172
TEST_P(ThreadPoolImplTest,WorkerThreadObserver)1173 TEST_P(ThreadPoolImplTest, WorkerThreadObserver) {
1174 auto owned_observer =
1175 std::make_unique<testing::StrictMock<test::MockWorkerThreadObserver>>();
1176 auto* observer = owned_observer.get();
1177 set_worker_thread_observer(std::move(owned_observer));
1178
1179 // A worker should be created for each thread group. After that, 4 threads
1180 // should be created for each SingleThreadTaskRunnerThreadMode (8 on Windows).
1181 const int kExpectedNumForegroundPoolWorkers = 1;
1182 const int kExpectedNumUtilityPoolWorkers =
1183 GetUseResourceEfficientThreadGroup() &&
1184 CanUseUtilityThreadTypeForWorkerThread()
1185 ? 1
1186 : 0;
1187 const int kExpectedNumBackgroundPoolWorkers =
1188 CanUseBackgroundThreadTypeForWorkerThread() ? 1 : 0;
1189 const int kExpectedNumPoolWorkers = kExpectedNumForegroundPoolWorkers +
1190 kExpectedNumUtilityPoolWorkers +
1191 kExpectedNumBackgroundPoolWorkers;
1192 const int kExpectedNumSharedSingleThreadedForegroundWorkers = 2;
1193 const int kExpectedNumSharedSingleThreadedUtilityWorkers =
1194 GetUseResourceEfficientThreadGroup() &&
1195 CanUseUtilityThreadTypeForWorkerThread()
1196 ? 2
1197 : 0;
1198 const int kExpectedNumSharedSingleThreadedBackgroundWorkers =
1199 CanUseBackgroundThreadTypeForWorkerThread() ? 2 : 0;
1200 const int kExpectedNumSharedSingleThreadedWorkers =
1201 kExpectedNumSharedSingleThreadedForegroundWorkers +
1202 kExpectedNumSharedSingleThreadedUtilityWorkers +
1203 kExpectedNumSharedSingleThreadedBackgroundWorkers;
1204 const int kExpectedNumDedicatedSingleThreadedWorkers = 6;
1205
1206 const int kExpectedNumCOMSharedSingleThreadedWorkers =
1207 #if BUILDFLAG(IS_WIN)
1208 kExpectedNumSharedSingleThreadedWorkers;
1209 #else
1210 0;
1211 #endif
1212 const int kExpectedNumCOMDedicatedSingleThreadedWorkers =
1213 #if BUILDFLAG(IS_WIN)
1214 kExpectedNumDedicatedSingleThreadedWorkers;
1215 #else
1216 0;
1217 #endif
1218
1219 EXPECT_CALL(*observer, OnWorkerThreadMainEntry())
1220 .Times(kExpectedNumPoolWorkers + kExpectedNumSharedSingleThreadedWorkers +
1221 kExpectedNumDedicatedSingleThreadedWorkers +
1222 kExpectedNumCOMSharedSingleThreadedWorkers +
1223 kExpectedNumCOMDedicatedSingleThreadedWorkers);
1224
1225 // Infinite detach time to prevent workers from invoking
1226 // OnWorkerThreadMainExit() earlier than expected.
1227 StartThreadPool(kMaxNumForegroundThreads, kMaxNumUtilityThreads,
1228 TimeDelta::Max());
1229
1230 std::vector<scoped_refptr<SingleThreadTaskRunner>> task_runners;
1231
1232 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1233 {TaskPriority::BEST_EFFORT}, SingleThreadTaskRunnerThreadMode::SHARED));
1234 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1235 {TaskPriority::BEST_EFFORT, MayBlock()},
1236 SingleThreadTaskRunnerThreadMode::SHARED));
1237 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1238 {TaskPriority::USER_VISIBLE}, SingleThreadTaskRunnerThreadMode::SHARED));
1239 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1240 {TaskPriority::USER_VISIBLE, MayBlock()},
1241 SingleThreadTaskRunnerThreadMode::SHARED));
1242 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1243 {TaskPriority::USER_BLOCKING}, SingleThreadTaskRunnerThreadMode::SHARED));
1244 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1245 {TaskPriority::USER_BLOCKING, MayBlock()},
1246 SingleThreadTaskRunnerThreadMode::SHARED));
1247
1248 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1249 {TaskPriority::BEST_EFFORT},
1250 SingleThreadTaskRunnerThreadMode::DEDICATED));
1251 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1252 {TaskPriority::BEST_EFFORT, MayBlock()},
1253 SingleThreadTaskRunnerThreadMode::DEDICATED));
1254 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1255 {TaskPriority::USER_VISIBLE},
1256 SingleThreadTaskRunnerThreadMode::DEDICATED));
1257 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1258 {TaskPriority::USER_VISIBLE, MayBlock()},
1259 SingleThreadTaskRunnerThreadMode::DEDICATED));
1260 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1261 {TaskPriority::USER_BLOCKING},
1262 SingleThreadTaskRunnerThreadMode::DEDICATED));
1263 task_runners.push_back(thread_pool_->CreateSingleThreadTaskRunner(
1264 {TaskPriority::USER_BLOCKING, MayBlock()},
1265 SingleThreadTaskRunnerThreadMode::DEDICATED));
1266
1267 #if BUILDFLAG(IS_WIN)
1268 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1269 {TaskPriority::BEST_EFFORT}, SingleThreadTaskRunnerThreadMode::SHARED));
1270 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1271 {TaskPriority::BEST_EFFORT, MayBlock()},
1272 SingleThreadTaskRunnerThreadMode::SHARED));
1273 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1274 {TaskPriority::USER_VISIBLE}, SingleThreadTaskRunnerThreadMode::SHARED));
1275 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1276 {TaskPriority::USER_VISIBLE, MayBlock()},
1277 SingleThreadTaskRunnerThreadMode::SHARED));
1278 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1279 {TaskPriority::USER_BLOCKING}, SingleThreadTaskRunnerThreadMode::SHARED));
1280 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1281 {TaskPriority::USER_BLOCKING, MayBlock()},
1282 SingleThreadTaskRunnerThreadMode::SHARED));
1283
1284 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1285 {TaskPriority::BEST_EFFORT},
1286 SingleThreadTaskRunnerThreadMode::DEDICATED));
1287 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1288 {TaskPriority::BEST_EFFORT, MayBlock()},
1289 SingleThreadTaskRunnerThreadMode::DEDICATED));
1290 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1291 {TaskPriority::USER_VISIBLE},
1292 SingleThreadTaskRunnerThreadMode::DEDICATED));
1293 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1294 {TaskPriority::USER_VISIBLE, MayBlock()},
1295 SingleThreadTaskRunnerThreadMode::DEDICATED));
1296 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1297 {TaskPriority::USER_BLOCKING},
1298 SingleThreadTaskRunnerThreadMode::DEDICATED));
1299 task_runners.push_back(thread_pool_->CreateCOMSTATaskRunner(
1300 {TaskPriority::USER_BLOCKING, MayBlock()},
1301 SingleThreadTaskRunnerThreadMode::DEDICATED));
1302 #endif
1303
1304 for (auto& task_runner : task_runners)
1305 task_runner->PostTask(FROM_HERE, DoNothing());
1306
1307 // Release single-threaded workers. This should cause dedicated workers to
1308 // invoke OnWorkerThreadMainExit().
1309 observer->AllowCallsOnMainExit(kExpectedNumDedicatedSingleThreadedWorkers +
1310 kExpectedNumCOMDedicatedSingleThreadedWorkers);
1311 task_runners.clear();
1312 observer->WaitCallsOnMainExit();
1313
1314 // Join all remaining workers. This should cause shared single-threaded
1315 // workers and thread pool workers to invoke OnWorkerThreadMainExit().
1316 observer->AllowCallsOnMainExit(kExpectedNumPoolWorkers +
1317 kExpectedNumSharedSingleThreadedWorkers +
1318 kExpectedNumCOMSharedSingleThreadedWorkers);
1319 TearDown();
1320 observer->WaitCallsOnMainExit();
1321 }
1322
1323 // Verify that a basic NotifyConcurrencyIncrease() runs the worker task.
TEST_P(ThreadPoolImplTest,BasicJob)1324 TEST_P(ThreadPoolImplTest, BasicJob) {
1325 StartThreadPool();
1326
1327 TestWaitableEvent threads_running;
1328
1329 auto job_task = base::MakeRefCounted<test::MockJobTask>(
1330 BindLambdaForTesting(
1331 [&threads_running](JobDelegate*) { threads_running.Signal(); }),
1332 /* num_tasks_to_run */ 1);
1333 scoped_refptr<JobTaskSource> task_source =
1334 job_task->GetJobTaskSource(FROM_HERE, {}, thread_pool_.get());
1335 task_source->NotifyConcurrencyIncrease();
1336
1337 threads_running.Wait();
1338 }
1339
1340 // Verify that max concurrency is eventually reached, but not exceeded, when
1341 // concurrency is increased from many workers.
TEST_P(ThreadPoolImplTest,ParallelJob)1342 TEST_P(ThreadPoolImplTest, ParallelJob) {
1343 constexpr size_t kTargetMaxConcurrency = 14;
1344 constexpr size_t kLargeThreadPoolSize = 15;
1345 StartThreadPool(/* max_num_foreground_threads=*/kLargeThreadPoolSize,
1346 kLargeThreadPoolSize);
1347
1348 // This test times out with the old job implementation.
1349 // Note: Exit after starting the Thread Pool since TearDown() expects the
1350 // ThreadPool to be started.
1351 if (!GetUseNewJobImplementation()) {
1352 return;
1353 }
1354
1355 std::atomic_size_t max_concurrency = 2;
1356 std::atomic_size_t num_workers = 0;
1357
1358 auto worker_task = BindLambdaForTesting([&](JobDelegate* delegate) {
1359 // Increase max concurrency if target is not reached.
1360 size_t current_max_concurrency =
1361 max_concurrency.load(std::memory_order_relaxed);
1362 while (current_max_concurrency < kTargetMaxConcurrency) {
1363 if (max_concurrency.compare_exchange_weak(current_max_concurrency,
1364 current_max_concurrency + 1,
1365 std::memory_order_relaxed)) {
1366 delegate->NotifyConcurrencyIncrease();
1367 break;
1368 }
1369 }
1370
1371 // Increase number of workers and verify that target max concurrency is not
1372 // exceeded.
1373 size_t current_num_workers =
1374 num_workers.fetch_add(1, std::memory_order_relaxed);
1375 EXPECT_LT(current_num_workers, kTargetMaxConcurrency);
1376
1377 // Busy wait until the target number of workers is reached.
1378 while (num_workers.load(std::memory_order_relaxed) <
1379 kTargetMaxConcurrency) {
1380 }
1381
1382 // Sleep to detect if too many workers run the worker task.
1383 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
1384
1385 // Force the job to exit by setting max concurrency to 0.
1386 max_concurrency.store(0, std::memory_order_relaxed);
1387 });
1388
1389 auto max_concurrency_callback =
1390 BindLambdaForTesting([&](size_t worker_count) {
1391 return max_concurrency.load(std::memory_order_relaxed);
1392 });
1393
1394 auto task_source = internal::CreateJobTaskSource(
1395 FROM_HERE, TaskTraits(), worker_task, max_concurrency_callback,
1396 thread_pool_.get());
1397 task_source->NotifyConcurrencyIncrease();
1398 thread_pool_->FlushForTesting();
1399
1400 EXPECT_EQ(num_workers, kTargetMaxConcurrency);
1401 }
1402
1403 // Verify that calling ShouldYield() returns true for a job task source that
1404 // needs to change thread group because of a priority update.
TEST_P(ThreadPoolImplTest,ThreadGroupChangeShouldYield)1405 TEST_P(ThreadPoolImplTest, ThreadGroupChangeShouldYield) {
1406 StartThreadPool();
1407
1408 TestWaitableEvent threads_running;
1409 TestWaitableEvent threads_continue;
1410
1411 auto job_task = base::MakeRefCounted<test::MockJobTask>(
1412 BindLambdaForTesting(
1413 [&threads_running, &threads_continue](JobDelegate* delegate) {
1414 EXPECT_FALSE(delegate->ShouldYield());
1415
1416 threads_running.Signal();
1417 threads_continue.Wait();
1418
1419 // The task source needs to yield if background thread groups exist.
1420 EXPECT_EQ(delegate->ShouldYield(),
1421 CanUseBackgroundThreadTypeForWorkerThread());
1422 }),
1423 /* num_tasks_to_run */ 1);
1424 scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
1425 FROM_HERE, {TaskPriority::USER_VISIBLE}, thread_pool_.get());
1426 task_source->NotifyConcurrencyIncrease();
1427
1428 threads_running.Wait();
1429 thread_pool_->UpdatePriority(task_source, TaskPriority::BEST_EFFORT);
1430 threads_continue.Signal();
1431
1432 // Flush the task tracker to be sure that no local variables are accessed by
1433 // tasks after the end of the scope.
1434 thread_pool_->FlushForTesting();
1435 }
1436
1437 namespace {
1438
1439 class MustBeDestroyed {
1440 public:
MustBeDestroyed(bool * was_destroyed)1441 explicit MustBeDestroyed(bool* was_destroyed)
1442 : was_destroyed_(was_destroyed) {}
1443 MustBeDestroyed(const MustBeDestroyed&) = delete;
1444 MustBeDestroyed& operator=(const MustBeDestroyed&) = delete;
~MustBeDestroyed()1445 ~MustBeDestroyed() { *was_destroyed_ = true; }
1446
1447 private:
1448 const raw_ptr<bool> was_destroyed_;
1449 };
1450
1451 } // namespace
1452
1453 // Regression test for https://crbug.com/945087.
TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,NoLeakWhenPostingNestedTask)1454 TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions,
1455 NoLeakWhenPostingNestedTask) {
1456 StartThreadPool();
1457
1458 SequenceLocalStorageSlot<std::unique_ptr<MustBeDestroyed>> sls;
1459
1460 bool was_destroyed = false;
1461 auto must_be_destroyed = std::make_unique<MustBeDestroyed>(&was_destroyed);
1462
1463 auto task_runner = CreateTaskRunnerAndExecutionMode(
1464 thread_pool_.get(), GetTraits(), GetExecutionMode());
1465
1466 task_runner->PostTask(FROM_HERE, BindLambdaForTesting([&] {
1467 sls.emplace(std::move(must_be_destroyed));
1468 task_runner->PostTask(FROM_HERE, DoNothing());
1469 }));
1470
1471 TearDown();
1472
1473 // The TaskRunner should be deleted along with the Sequence and its
1474 // SequenceLocalStorage when dropping this reference.
1475 task_runner = nullptr;
1476
1477 EXPECT_TRUE(was_destroyed);
1478 }
1479
1480 namespace {
1481
1482 struct TaskRunnerAndEvents {
TaskRunnerAndEventsbase::internal::__anonf5bd97a01c11::TaskRunnerAndEvents1483 TaskRunnerAndEvents(scoped_refptr<UpdateableSequencedTaskRunner> task_runner,
1484 const TaskPriority updated_priority,
1485 TestWaitableEvent* expected_previous_event)
1486 : task_runner(std::move(task_runner)),
1487 updated_priority(updated_priority),
1488 expected_previous_event(expected_previous_event) {}
1489
1490 // The UpdateableSequencedTaskRunner.
1491 scoped_refptr<UpdateableSequencedTaskRunner> task_runner;
1492
1493 // The priority to use in UpdatePriority().
1494 const TaskPriority updated_priority;
1495
1496 // Signaled when a task blocking |task_runner| is scheduled.
1497 TestWaitableEvent scheduled;
1498
1499 // Signaled to release the task blocking |task_runner|.
1500 TestWaitableEvent blocked;
1501
1502 // Signaled in the task that runs following the priority update.
1503 TestWaitableEvent task_ran;
1504
1505 // An event that should be signaled before the task following the priority
1506 // update runs.
1507 raw_ptr<TestWaitableEvent> expected_previous_event;
1508 };
1509
1510 // Create a series of sample task runners that will post tasks at various
1511 // initial priorities, then update priority.
CreateTaskRunnersAndEvents(ThreadPoolImplTest * test,ThreadPolicy thread_policy)1512 std::vector<std::unique_ptr<TaskRunnerAndEvents>> CreateTaskRunnersAndEvents(
1513 ThreadPoolImplTest* test,
1514 ThreadPolicy thread_policy) {
1515 ThreadPoolImpl* thread_pool = test->thread_pool_.get();
1516 std::vector<std::unique_ptr<TaskRunnerAndEvents>> task_runners_and_events;
1517
1518 // -----
1519 // Task runner that will start as USER_VISIBLE and update to USER_BLOCKING.
1520 // Its task is expected to run first.
1521 task_runners_and_events.push_back(std::make_unique<TaskRunnerAndEvents>(
1522 thread_pool->CreateUpdateableSequencedTaskRunner(
1523 TaskTraits({TaskPriority::USER_VISIBLE, thread_policy})),
1524 TaskPriority::USER_BLOCKING, nullptr));
1525
1526 // -----
1527 // Task runner that will start as BEST_EFFORT and update to USER_VISIBLE.
1528 // Its task is expected to run after the USER_BLOCKING task runner's task,
1529 // unless resource-efficient thread group exists, in which case they will run
1530 // asynchronously.
1531 TestWaitableEvent* expected_previous_event =
1532 test->GetUseResourceEfficientThreadGroup()
1533 ? nullptr
1534 : &task_runners_and_events.back()->task_ran;
1535 task_runners_and_events.push_back(std::make_unique<TaskRunnerAndEvents>(
1536 thread_pool->CreateUpdateableSequencedTaskRunner(
1537 {TaskPriority::BEST_EFFORT, thread_policy}),
1538 TaskPriority::USER_VISIBLE, expected_previous_event));
1539
1540 // -----
1541 // Task runner that will start as USER_BLOCKING and update to BEST_EFFORT. Its
1542 // task is expected to run asynchronously with the other two task runners'
1543 // tasks if background thread groups exist, or after the USER_VISIBLE task
1544 // runner's task if not.
1545 //
1546 // If the task following the priority update is expected to run in the
1547 // foreground group, it should be after the task posted to the TaskRunner
1548 // whose priority is updated to USER_VISIBLE.
1549 expected_previous_event =
1550 CanUseBackgroundThreadTypeForWorkerThread() ||
1551 (test->GetUseResourceEfficientThreadGroup() &&
1552 CanUseUtilityThreadTypeForWorkerThread())
1553 ? nullptr
1554 : &task_runners_and_events.back()->task_ran;
1555
1556 task_runners_and_events.push_back(std::make_unique<TaskRunnerAndEvents>(
1557 thread_pool->CreateUpdateableSequencedTaskRunner(
1558 TaskTraits({TaskPriority::USER_BLOCKING, thread_policy})),
1559 TaskPriority::BEST_EFFORT, expected_previous_event));
1560
1561 return task_runners_and_events;
1562 }
1563
1564 // Update the priority of a sequence when it is not scheduled.
TestUpdatePrioritySequenceNotScheduled(ThreadPoolImplTest * test,ThreadPolicy thread_policy)1565 void TestUpdatePrioritySequenceNotScheduled(ThreadPoolImplTest* test,
1566 ThreadPolicy thread_policy) {
1567 // This test verifies that tasks run in priority order. With more than 1
1568 // thread per pool, it is possible that tasks don't run in order even if
1569 // threads got tasks from the PriorityQueue in order. Therefore, enforce a
1570 // maximum of 1 thread per pool.
1571 constexpr size_t kLocalMaxNumForegroundThreads = 1;
1572
1573 test->StartThreadPool(kLocalMaxNumForegroundThreads);
1574 auto task_runners_and_events =
1575 CreateTaskRunnersAndEvents(test, thread_policy);
1576
1577 // Prevent tasks from running.
1578 test->thread_pool_->BeginFence();
1579
1580 // Post tasks to multiple task runners while they are at initial priority.
1581 // They won't run immediately because of the call to BeginFence() above.
1582 for (auto& task_runner_and_events : task_runners_and_events) {
1583 task_runner_and_events->task_runner->PostTask(
1584 FROM_HERE,
1585 BindOnce(
1586 &VerifyOrderAndTaskEnvironmentAndSignalEvent,
1587 TaskTraits{task_runner_and_events->updated_priority, thread_policy},
1588 test->GetUseResourceEfficientThreadGroup(),
1589 Unretained(task_runner_and_events->expected_previous_event.get()),
1590 Unretained(&task_runner_and_events->task_ran)));
1591 }
1592
1593 // Update the priorities of the task runners that posted the tasks.
1594 for (auto& task_runner_and_events : task_runners_and_events) {
1595 task_runner_and_events->task_runner->UpdatePriority(
1596 task_runner_and_events->updated_priority);
1597 }
1598
1599 // Allow tasks to run.
1600 test->thread_pool_->EndFence();
1601
1602 for (auto& task_runner_and_events : task_runners_and_events)
1603 task_runner_and_events->task_ran.Wait();
1604 }
1605
1606 // Update the priority of a sequence when it is scheduled, i.e. not currently
1607 // in a priority queue.
TestUpdatePrioritySequenceScheduled(ThreadPoolImplTest * test,ThreadPolicy thread_policy)1608 void TestUpdatePrioritySequenceScheduled(ThreadPoolImplTest* test,
1609 ThreadPolicy thread_policy) {
1610 test->StartThreadPool();
1611 auto task_runners_and_events =
1612 CreateTaskRunnersAndEvents(test, thread_policy);
1613
1614 // Post blocking tasks to all task runners to prevent tasks from being
1615 // scheduled later in the test.
1616 for (auto& task_runner_and_events : task_runners_and_events) {
1617 task_runner_and_events->task_runner->PostTask(
1618 FROM_HERE, BindLambdaForTesting([&]() {
1619 task_runner_and_events->scheduled.Signal();
1620 task_runner_and_events->blocked.Wait();
1621 }));
1622
1623 task_runner_and_events->scheduled.Wait();
1624 }
1625
1626 // Update the priorities of the task runners while they are scheduled and
1627 // blocked.
1628 for (auto& task_runner_and_events : task_runners_and_events) {
1629 task_runner_and_events->task_runner->UpdatePriority(
1630 task_runner_and_events->updated_priority);
1631 }
1632
1633 // Post an additional task to each task runner.
1634 for (auto& task_runner_and_events : task_runners_and_events) {
1635 task_runner_and_events->task_runner->PostTask(
1636 FROM_HERE,
1637 BindOnce(
1638 &VerifyOrderAndTaskEnvironmentAndSignalEvent,
1639 TaskTraits{task_runner_and_events->updated_priority, thread_policy},
1640 test->GetUseResourceEfficientThreadGroup(),
1641 Unretained(task_runner_and_events->expected_previous_event),
1642 Unretained(&task_runner_and_events->task_ran)));
1643 }
1644
1645 // Unblock the task blocking each task runner, allowing the additional posted
1646 // tasks to run. Each posted task will verify that it has been posted with
1647 // updated priority when it runs.
1648 for (auto& task_runner_and_events : task_runners_and_events) {
1649 task_runner_and_events->blocked.Signal();
1650 task_runner_and_events->task_ran.Wait();
1651 }
1652 }
1653
1654 } // namespace
1655
TEST_P(ThreadPoolImplTest,UpdatePrioritySequenceNotScheduled_PreferBackground)1656 TEST_P(ThreadPoolImplTest,
1657 UpdatePrioritySequenceNotScheduled_PreferBackground) {
1658 TestUpdatePrioritySequenceNotScheduled(this, ThreadPolicy::PREFER_BACKGROUND);
1659 }
1660
TEST_P(ThreadPoolImplTest,UpdatePrioritySequenceNotScheduled_MustUseForeground)1661 TEST_P(ThreadPoolImplTest,
1662 UpdatePrioritySequenceNotScheduled_MustUseForeground) {
1663 TestUpdatePrioritySequenceNotScheduled(this,
1664 ThreadPolicy::MUST_USE_FOREGROUND);
1665 }
1666
TEST_P(ThreadPoolImplTest,UpdatePrioritySequenceScheduled_PreferBackground)1667 TEST_P(ThreadPoolImplTest, UpdatePrioritySequenceScheduled_PreferBackground) {
1668 TestUpdatePrioritySequenceScheduled(this, ThreadPolicy::PREFER_BACKGROUND);
1669 }
1670
TEST_P(ThreadPoolImplTest,UpdatePrioritySequenceScheduled_MustUseForeground)1671 TEST_P(ThreadPoolImplTest, UpdatePrioritySequenceScheduled_MustUseForeground) {
1672 TestUpdatePrioritySequenceScheduled(this, ThreadPolicy::MUST_USE_FOREGROUND);
1673 }
1674
1675 // Verify that a ThreadPolicy has to be specified in TaskTraits to increase
1676 // TaskPriority from BEST_EFFORT.
TEST_P(ThreadPoolImplTest,UpdatePriorityFromBestEffortNoThreadPolicy)1677 TEST_P(ThreadPoolImplTest, UpdatePriorityFromBestEffortNoThreadPolicy) {
1678 GTEST_FLAG_SET(death_test_style, "threadsafe");
1679 StartThreadPool();
1680 {
1681 auto task_runner = thread_pool_->CreateUpdateableSequencedTaskRunner(
1682 {TaskPriority::BEST_EFFORT});
1683 EXPECT_DCHECK_DEATH(
1684 { task_runner->UpdatePriority(TaskPriority::USER_VISIBLE); });
1685 }
1686 {
1687 auto task_runner = thread_pool_->CreateUpdateableSequencedTaskRunner(
1688 {TaskPriority::BEST_EFFORT});
1689 EXPECT_DCHECK_DEATH(
1690 { task_runner->UpdatePriority(TaskPriority::USER_BLOCKING); });
1691 }
1692 }
1693
1694 INSTANTIATE_TEST_SUITE_P(
1695 ,
1696 ThreadPoolImplTest,
1697 ::testing::Values(
1698 // Param 1: Use resource efficient thread group.
1699 // Param 2: Use new job implementation.
1700 std::make_pair(true, false),
1701 std::make_pair(false, false),
1702 std::make_pair(false, true)),
__anonf5bd97a01e02(const testing::TestParamInfo<std::pair<bool, bool>>& info) 1703 [](const testing::TestParamInfo<std::pair<bool, bool>>& info) {
1704 return base::StrCat(
1705 {info.param.first ? "EfficientThreadGroup" : "NoEfficientThreadGroup",
1706 info.param.second ? "NewJob" : "OldJob"});
1707 });
1708
1709 INSTANTIATE_TEST_SUITE_P(
1710 All,
1711 ThreadPoolImplTest_CoverAllSchedulingOptions,
1712 ::testing::Combine(
1713 ::testing::Bool(),
1714 ::testing::ValuesIn(
1715 GetTraitsExecutionModePairsToCoverAllSchedulingOptions())));
1716
1717 } // namespace internal
1718 } // namespace base
1719