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