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 <algorithm>
8 #include <optional>
9 #include <string>
10 #include <string_view>
11 #include <utility>
12
13 #include "base/base_switches.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/debug/leak_annotations.h"
17 #include "base/feature_list.h"
18 #include "base/functional/bind.h"
19 #include "base/functional/callback_helpers.h"
20 #include "base/message_loop/message_pump.h"
21 #include "base/message_loop/message_pump_type.h"
22 #include "base/metrics/field_trial_params.h"
23 #include "base/strings/string_util.h"
24 #include "base/system/sys_info.h"
25 #include "base/task/scoped_set_task_priority_for_current_thread.h"
26 #include "base/task/thread_pool/pooled_parallel_task_runner.h"
27 #include "base/task/thread_pool/pooled_sequenced_task_runner.h"
28 #include "base/task/thread_pool/task.h"
29 #include "base/task/thread_pool/task_source.h"
30 #include "base/task/thread_pool/task_source_sort_key.h"
31 #include "base/task/thread_pool/thread_group_impl.h"
32 #include "base/task/thread_pool/worker_thread.h"
33 #include "base/thread_annotations.h"
34 #include "base/threading/platform_thread.h"
35 #include "base/time/time.h"
36 #include "build/build_config.h"
37
38 namespace base {
39 namespace internal {
40
41 namespace {
42
43 constexpr EnvironmentParams kForegroundPoolEnvironmentParams{
44 "Foreground", base::ThreadType::kDefault};
45
46 constexpr EnvironmentParams kUtilityPoolEnvironmentParams{
47 "Utility", base::ThreadType::kUtility};
48
49 constexpr EnvironmentParams kBackgroundPoolEnvironmentParams{
50 "Background", base::ThreadType::kBackground};
51
52 constexpr size_t kMaxBestEffortTasks = 2;
53
54 // Indicates whether BEST_EFFORT tasks are disabled by a command line switch.
HasDisableBestEffortTasksSwitch()55 bool HasDisableBestEffortTasksSwitch() {
56 // The CommandLine might not be initialized if ThreadPool is initialized in a
57 // dynamic library which doesn't have access to argc/argv.
58 return CommandLine::InitializedForCurrentProcess() &&
59 CommandLine::ForCurrentProcess()->HasSwitch(
60 switches::kDisableBestEffortTasks);
61 }
62
63 // A global variable that can be set from test fixtures while no
64 // ThreadPoolInstance is active. Global instead of being a member variable to
65 // avoid having to add a public API to ThreadPoolInstance::InitParams for this
66 // internal edge case.
67 bool g_synchronous_thread_start_for_testing = false;
68
69 } // namespace
70
ThreadPoolImpl(std::string_view histogram_label)71 ThreadPoolImpl::ThreadPoolImpl(std::string_view histogram_label)
72 : ThreadPoolImpl(histogram_label, std::make_unique<TaskTrackerImpl>()) {}
73
ThreadPoolImpl(std::string_view histogram_label,std::unique_ptr<TaskTrackerImpl> task_tracker,bool use_background_threads)74 ThreadPoolImpl::ThreadPoolImpl(std::string_view histogram_label,
75 std::unique_ptr<TaskTrackerImpl> task_tracker,
76 bool use_background_threads)
77 : histogram_label_(histogram_label),
78 task_tracker_(std::move(task_tracker)),
79 use_background_threads_(use_background_threads),
80 single_thread_task_runner_manager_(task_tracker_->GetTrackedRef(),
81 &delayed_task_manager_),
82 has_disable_best_effort_switch_(HasDisableBestEffortTasksSwitch()),
83 tracked_ref_factory_(this) {
84 foreground_thread_group_ = std::make_unique<ThreadGroupImpl>(
85 histogram_label.empty()
86 ? std::string()
87 : JoinString(
88 {histogram_label, kForegroundPoolEnvironmentParams.name_suffix},
89 "."),
90 kForegroundPoolEnvironmentParams.name_suffix,
91 kForegroundPoolEnvironmentParams.thread_type_hint,
92 task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef());
93
94 if (CanUseBackgroundThreadTypeForWorkerThread()) {
95 background_thread_group_ = std::make_unique<ThreadGroupImpl>(
96 histogram_label.empty()
97 ? std::string()
98 : JoinString({histogram_label,
99 kBackgroundPoolEnvironmentParams.name_suffix},
100 "."),
101 kBackgroundPoolEnvironmentParams.name_suffix,
102 use_background_threads
103 ? kBackgroundPoolEnvironmentParams.thread_type_hint
104 : kForegroundPoolEnvironmentParams.thread_type_hint,
105 task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef());
106 }
107 }
108
~ThreadPoolImpl()109 ThreadPoolImpl::~ThreadPoolImpl() {
110 #if DCHECK_IS_ON()
111 DCHECK(join_for_testing_returned_.IsSet());
112 #endif
113
114 // Reset thread groups to release held TrackedRefs, which block teardown.
115 foreground_thread_group_.reset();
116 utility_thread_group_.reset();
117 background_thread_group_.reset();
118 }
119
Start(const ThreadPoolInstance::InitParams & init_params,WorkerThreadObserver * worker_thread_observer)120 void ThreadPoolImpl::Start(const ThreadPoolInstance::InitParams& init_params,
121 WorkerThreadObserver* worker_thread_observer) {
122 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
123 DCHECK(!started_);
124
125 // The max number of concurrent BEST_EFFORT tasks is |kMaxBestEffortTasks|,
126 // unless the max number of foreground threads is lower.
127 size_t max_best_effort_tasks =
128 std::min(kMaxBestEffortTasks, init_params.max_num_foreground_threads);
129
130 // Start the service thread. On platforms that support it (POSIX except NaCL
131 // SFI), the service thread runs a MessageLoopForIO which is used to support
132 // FileDescriptorWatcher in the scope in which tasks run.
133 ServiceThread::Options service_thread_options;
134 service_thread_options.message_pump_type =
135 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
136 MessagePumpType::IO;
137 #else
138 MessagePumpType::DEFAULT;
139 #endif
140 CHECK(service_thread_.StartWithOptions(std::move(service_thread_options)));
141 if (g_synchronous_thread_start_for_testing)
142 service_thread_.WaitUntilThreadStarted();
143
144 if (FeatureList::IsEnabled(kUseUtilityThreadGroup) &&
145 CanUseUtilityThreadTypeForWorkerThread()) {
146 utility_thread_group_ = std::make_unique<ThreadGroupImpl>(
147 histogram_label_.empty()
148 ? std::string()
149 : JoinString(
150 {histogram_label_, kUtilityPoolEnvironmentParams.name_suffix},
151 "."),
152 kUtilityPoolEnvironmentParams.name_suffix,
153 kUtilityPoolEnvironmentParams.thread_type_hint,
154 task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef());
155 foreground_thread_group_
156 ->HandoffNonUserBlockingTaskSourcesToOtherThreadGroup(
157 utility_thread_group_.get());
158 }
159
160 // Update the CanRunPolicy based on |has_disable_best_effort_switch_|.
161 UpdateCanRunPolicy();
162
163 // Needs to happen after starting the service thread to get its task_runner().
164 auto service_thread_task_runner = service_thread_.task_runner();
165 delayed_task_manager_.Start(service_thread_task_runner);
166
167 single_thread_task_runner_manager_.Start(service_thread_task_runner,
168 worker_thread_observer);
169
170 ThreadGroup::WorkerEnvironment worker_environment;
171 switch (init_params.common_thread_pool_environment) {
172 case InitParams::CommonThreadPoolEnvironment::DEFAULT:
173 worker_environment = ThreadGroup::WorkerEnvironment::NONE;
174 break;
175 #if BUILDFLAG(IS_WIN)
176 case InitParams::CommonThreadPoolEnvironment::COM_MTA:
177 worker_environment = ThreadGroup::WorkerEnvironment::COM_MTA;
178 break;
179 #endif
180 }
181
182 size_t foreground_threads = init_params.max_num_foreground_threads;
183 size_t utility_threads = init_params.max_num_utility_threads;
184
185 // On platforms that can't use the background thread priority, best-effort
186 // tasks run in foreground pools. A cap is set on the number of best-effort
187 // tasks that can run in foreground pools to ensure that there is always
188 // room for incoming foreground tasks and to minimize the performance impact
189 // of best-effort tasks.
190 foreground_thread_group_.get()->Start(
191 foreground_threads, max_best_effort_tasks,
192 init_params.suggested_reclaim_time, service_thread_task_runner,
193 worker_thread_observer, worker_environment,
194 g_synchronous_thread_start_for_testing,
195 /*may_block_threshold=*/{});
196
197 if (utility_thread_group_) {
198 utility_thread_group_.get()->Start(
199 utility_threads, max_best_effort_tasks,
200 init_params.suggested_reclaim_time, service_thread_task_runner,
201 worker_thread_observer, worker_environment,
202 g_synchronous_thread_start_for_testing,
203 /*may_block_threshold=*/{});
204 }
205
206 if (background_thread_group_) {
207 background_thread_group_.get()->Start(
208 max_best_effort_tasks, max_best_effort_tasks,
209 init_params.suggested_reclaim_time, service_thread_task_runner,
210 worker_thread_observer, worker_environment,
211 g_synchronous_thread_start_for_testing,
212 /*may_block_threshold=*/{});
213 }
214
215 started_ = true;
216 }
217
WasStarted() const218 bool ThreadPoolImpl::WasStarted() const {
219 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
220 return started_;
221 }
222
WasStartedUnsafe() const223 bool ThreadPoolImpl::WasStartedUnsafe() const {
224 return TS_UNCHECKED_READ(started_);
225 }
226
BeginRestrictedTasks()227 void ThreadPoolImpl::BeginRestrictedTasks() {
228 foreground_thread_group_->SetMaxTasks(2);
229 if (utility_thread_group_) {
230 utility_thread_group_->SetMaxTasks(1);
231 }
232 if (background_thread_group_) {
233 background_thread_group_->SetMaxTasks(1);
234 }
235 }
236
EndRestrictedTasks()237 void ThreadPoolImpl::EndRestrictedTasks() {
238 foreground_thread_group_->ResetMaxTasks();
239 if (utility_thread_group_) {
240 utility_thread_group_->ResetMaxTasks();
241 }
242 if (background_thread_group_) {
243 background_thread_group_->ResetMaxTasks();
244 }
245 }
246
PostDelayedTask(const Location & from_here,const TaskTraits & traits,OnceClosure task,TimeDelta delay)247 bool ThreadPoolImpl::PostDelayedTask(const Location& from_here,
248 const TaskTraits& traits,
249 OnceClosure task,
250 TimeDelta delay) {
251 // Post |task| as part of a one-off single-task Sequence.
252 return PostTaskWithSequence(
253 Task(from_here, std::move(task), TimeTicks::Now(), delay,
254 MessagePump::GetLeewayIgnoringThreadOverride()),
255 MakeRefCounted<Sequence>(traits, nullptr,
256 TaskSourceExecutionMode::kParallel));
257 }
258
CreateTaskRunner(const TaskTraits & traits)259 scoped_refptr<TaskRunner> ThreadPoolImpl::CreateTaskRunner(
260 const TaskTraits& traits) {
261 return MakeRefCounted<PooledParallelTaskRunner>(traits, this);
262 }
263
CreateSequencedTaskRunner(const TaskTraits & traits)264 scoped_refptr<SequencedTaskRunner> ThreadPoolImpl::CreateSequencedTaskRunner(
265 const TaskTraits& traits) {
266 return MakeRefCounted<PooledSequencedTaskRunner>(traits, this);
267 }
268
269 scoped_refptr<SingleThreadTaskRunner>
CreateSingleThreadTaskRunner(const TaskTraits & traits,SingleThreadTaskRunnerThreadMode thread_mode)270 ThreadPoolImpl::CreateSingleThreadTaskRunner(
271 const TaskTraits& traits,
272 SingleThreadTaskRunnerThreadMode thread_mode) {
273 return single_thread_task_runner_manager_.CreateSingleThreadTaskRunner(
274 traits, thread_mode);
275 }
276
277 #if BUILDFLAG(IS_WIN)
CreateCOMSTATaskRunner(const TaskTraits & traits,SingleThreadTaskRunnerThreadMode thread_mode)278 scoped_refptr<SingleThreadTaskRunner> ThreadPoolImpl::CreateCOMSTATaskRunner(
279 const TaskTraits& traits,
280 SingleThreadTaskRunnerThreadMode thread_mode) {
281 return single_thread_task_runner_manager_.CreateCOMSTATaskRunner(traits,
282 thread_mode);
283 }
284 #endif // BUILDFLAG(IS_WIN)
285
286 scoped_refptr<UpdateableSequencedTaskRunner>
CreateUpdateableSequencedTaskRunner(const TaskTraits & traits)287 ThreadPoolImpl::CreateUpdateableSequencedTaskRunner(const TaskTraits& traits) {
288 return MakeRefCounted<PooledSequencedTaskRunner>(traits, this);
289 }
290
NextScheduledRunTimeForTesting() const291 std::optional<TimeTicks> ThreadPoolImpl::NextScheduledRunTimeForTesting()
292 const {
293 if (task_tracker_->HasIncompleteTaskSourcesForTesting())
294 return TimeTicks::Now();
295 return delayed_task_manager_.NextScheduledRunTime();
296 }
297
ProcessRipeDelayedTasksForTesting()298 void ThreadPoolImpl::ProcessRipeDelayedTasksForTesting() {
299 delayed_task_manager_.ProcessRipeTasks();
300 }
301
302 // static
SetSynchronousThreadStartForTesting(bool enabled)303 void ThreadPoolImpl::SetSynchronousThreadStartForTesting(bool enabled) {
304 DCHECK(!ThreadPoolInstance::Get());
305 g_synchronous_thread_start_for_testing = enabled;
306 }
307
GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(const TaskTraits & traits) const308 size_t ThreadPoolImpl::GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
309 const TaskTraits& traits) const {
310 // This method does not support getting the maximum number of BEST_EFFORT
311 // tasks that can run concurrently in a pool.
312 DCHECK_NE(traits.priority(), TaskPriority::BEST_EFFORT);
313 return GetThreadGroupForTraits(traits)
314 ->GetMaxConcurrentNonBlockedTasksDeprecated();
315 }
316
Shutdown()317 void ThreadPoolImpl::Shutdown() {
318 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
319
320 // Cancels an internal service thread task. This must be done before stopping
321 // the service thread.
322 delayed_task_manager_.Shutdown();
323
324 // Stop() the ServiceThread before triggering shutdown. This ensures that no
325 // more delayed tasks or file descriptor watches will trigger during shutdown
326 // (preventing http://crbug.com/698140). None of these asynchronous tasks
327 // being guaranteed to happen anyways, stopping right away is valid behavior
328 // and avoids the more complex alternative of shutting down the service thread
329 // atomically during TaskTracker shutdown.
330 service_thread_.Stop();
331
332 task_tracker_->StartShutdown();
333
334 // Allow all tasks to run. Done after initiating shutdown to ensure that non-
335 // BLOCK_SHUTDOWN tasks don't get a chance to run and that BLOCK_SHUTDOWN
336 // tasks run with a normal thread priority.
337 UpdateCanRunPolicy();
338
339 // Ensures that there are enough background worker to run BLOCK_SHUTDOWN
340 // tasks.
341 foreground_thread_group_->OnShutdownStarted();
342 if (utility_thread_group_)
343 utility_thread_group_->OnShutdownStarted();
344 if (background_thread_group_)
345 background_thread_group_->OnShutdownStarted();
346
347 task_tracker_->CompleteShutdown();
348 }
349
FlushForTesting()350 void ThreadPoolImpl::FlushForTesting() {
351 task_tracker_->FlushForTesting();
352 }
353
FlushAsyncForTesting(OnceClosure flush_callback)354 void ThreadPoolImpl::FlushAsyncForTesting(OnceClosure flush_callback) {
355 task_tracker_->FlushAsyncForTesting(std::move(flush_callback));
356 }
357
JoinForTesting()358 void ThreadPoolImpl::JoinForTesting() {
359 #if DCHECK_IS_ON()
360 DCHECK(!join_for_testing_returned_.IsSet());
361 #endif
362 // Cancels an internal service thread task. This must be done before stopping
363 // the service thread.
364 delayed_task_manager_.Shutdown();
365 // The service thread must be stopped before the workers are joined, otherwise
366 // tasks scheduled by the DelayedTaskManager might be posted between joining
367 // those workers and stopping the service thread which will cause a CHECK. See
368 // https://crbug.com/771701.
369 service_thread_.Stop();
370 single_thread_task_runner_manager_.JoinForTesting();
371 foreground_thread_group_->JoinForTesting();
372 if (utility_thread_group_)
373 utility_thread_group_->JoinForTesting(); // IN-TEST
374 if (background_thread_group_)
375 background_thread_group_->JoinForTesting();
376 #if DCHECK_IS_ON()
377 join_for_testing_returned_.Set();
378 #endif
379 }
380
BeginFence()381 void ThreadPoolImpl::BeginFence() {
382 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
383 ++num_fences_;
384 UpdateCanRunPolicy();
385 }
386
EndFence()387 void ThreadPoolImpl::EndFence() {
388 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
389 DCHECK_GT(num_fences_, 0);
390 --num_fences_;
391 UpdateCanRunPolicy();
392 }
393
BeginBestEffortFence()394 void ThreadPoolImpl::BeginBestEffortFence() {
395 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
396 ++num_best_effort_fences_;
397 UpdateCanRunPolicy();
398 }
399
EndBestEffortFence()400 void ThreadPoolImpl::EndBestEffortFence() {
401 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
402 DCHECK_GT(num_best_effort_fences_, 0);
403 --num_best_effort_fences_;
404 UpdateCanRunPolicy();
405 }
406
BeginFizzlingBlockShutdownTasks()407 void ThreadPoolImpl::BeginFizzlingBlockShutdownTasks() {
408 task_tracker_->BeginFizzlingBlockShutdownTasks();
409 }
410
EndFizzlingBlockShutdownTasks()411 void ThreadPoolImpl::EndFizzlingBlockShutdownTasks() {
412 task_tracker_->EndFizzlingBlockShutdownTasks();
413 }
414
PostTaskWithSequenceNow(Task task,scoped_refptr<Sequence> sequence)415 bool ThreadPoolImpl::PostTaskWithSequenceNow(Task task,
416 scoped_refptr<Sequence> sequence) {
417 auto transaction = sequence->BeginTransaction();
418 const bool sequence_should_be_queued = transaction.WillPushImmediateTask();
419 RegisteredTaskSource task_source;
420 if (sequence_should_be_queued) {
421 task_source = task_tracker_->RegisterTaskSource(sequence);
422 // We shouldn't push |task| if we're not allowed to queue |task_source|.
423 if (!task_source)
424 return false;
425 }
426 if (!task_tracker_->WillPostTaskNow(task, transaction.traits().priority()))
427 return false;
428 transaction.PushImmediateTask(std::move(task));
429 if (task_source) {
430 const TaskTraits traits = transaction.traits();
431 GetThreadGroupForTraits(traits)->PushTaskSourceAndWakeUpWorkers(
432 {std::move(task_source), std::move(transaction)});
433 }
434 return true;
435 }
436
PostTaskWithSequence(Task task,scoped_refptr<Sequence> sequence)437 bool ThreadPoolImpl::PostTaskWithSequence(Task task,
438 scoped_refptr<Sequence> sequence) {
439 // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
440 // for details.
441 CHECK(task.task);
442 DCHECK(sequence);
443
444 if (!task_tracker_->WillPostTask(&task, sequence->shutdown_behavior())) {
445 // `task`'s destructor may run sequence-affine code, so it must be leaked
446 // when `WillPostTask` returns false.
447 auto leak = std::make_unique<Task>(std::move(task));
448 ANNOTATE_LEAKING_OBJECT_PTR(leak.get());
449 leak.release();
450 return false;
451 }
452
453 if (task.delayed_run_time.is_null()) {
454 return PostTaskWithSequenceNow(std::move(task), std::move(sequence));
455 } else {
456 // It's safe to take a ref on this pointer since the caller must have a ref
457 // to the TaskRunner in order to post.
458 scoped_refptr<TaskRunner> task_runner = sequence->task_runner();
459 delayed_task_manager_.AddDelayedTask(
460 std::move(task),
461 BindOnce(
462 [](scoped_refptr<Sequence> sequence,
463 ThreadPoolImpl* thread_pool_impl, scoped_refptr<TaskRunner>,
464 Task task) {
465 thread_pool_impl->PostTaskWithSequenceNow(std::move(task),
466 std::move(sequence));
467 },
468 std::move(sequence), Unretained(this), std::move(task_runner)));
469 }
470
471 return true;
472 }
473
ShouldYield(const TaskSource * task_source)474 bool ThreadPoolImpl::ShouldYield(const TaskSource* task_source) {
475 const TaskPriority priority = task_source->priority_racy();
476 auto* const thread_group =
477 GetThreadGroupForTraits({priority, task_source->thread_policy()});
478 // A task whose priority changed and is now running in the wrong thread group
479 // should yield so it's rescheduled in the right one.
480 if (!thread_group->IsBoundToCurrentThread())
481 return true;
482 return GetThreadGroupForTraits({priority, task_source->thread_policy()})
483 ->ShouldYield(task_source->GetSortKey());
484 }
485
EnqueueJobTaskSource(scoped_refptr<JobTaskSource> task_source)486 bool ThreadPoolImpl::EnqueueJobTaskSource(
487 scoped_refptr<JobTaskSource> task_source) {
488 auto registered_task_source =
489 task_tracker_->RegisterTaskSource(std::move(task_source));
490 if (!registered_task_source)
491 return false;
492 task_tracker_->WillEnqueueJob(
493 static_cast<JobTaskSource*>(registered_task_source.get()));
494 auto transaction = registered_task_source->BeginTransaction();
495 const TaskTraits traits = transaction.traits();
496 GetThreadGroupForTraits(traits)->PushTaskSourceAndWakeUpWorkers(
497 {std::move(registered_task_source), std::move(transaction)});
498 return true;
499 }
500
RemoveJobTaskSource(scoped_refptr<JobTaskSource> task_source)501 void ThreadPoolImpl::RemoveJobTaskSource(
502 scoped_refptr<JobTaskSource> task_source) {
503 auto transaction = task_source->BeginTransaction();
504 ThreadGroup* const current_thread_group =
505 GetThreadGroupForTraits(transaction.traits());
506 current_thread_group->RemoveTaskSource(*task_source);
507 }
508
UpdatePriority(scoped_refptr<TaskSource> task_source,TaskPriority priority)509 void ThreadPoolImpl::UpdatePriority(scoped_refptr<TaskSource> task_source,
510 TaskPriority priority) {
511 auto transaction = task_source->BeginTransaction();
512
513 if (transaction.traits().priority() == priority)
514 return;
515
516 if (transaction.traits().priority() == TaskPriority::BEST_EFFORT) {
517 DCHECK(transaction.traits().thread_policy_set_explicitly())
518 << "A ThreadPolicy must be specified in the TaskTraits of an "
519 "UpdateableSequencedTaskRunner whose priority is increased from "
520 "BEST_EFFORT. See ThreadPolicy documentation.";
521 }
522
523 ThreadGroup* const current_thread_group =
524 GetThreadGroupForTraits(transaction.traits());
525 transaction.UpdatePriority(priority);
526 ThreadGroup* const new_thread_group =
527 GetThreadGroupForTraits(transaction.traits());
528
529 if (new_thread_group == current_thread_group) {
530 // |task_source|'s position needs to be updated within its current thread
531 // group.
532 current_thread_group->UpdateSortKey(std::move(transaction));
533 } else {
534 // |task_source| is changing thread groups; remove it from its current
535 // thread group and reenqueue it.
536 auto registered_task_source =
537 current_thread_group->RemoveTaskSource(*task_source);
538 if (registered_task_source) {
539 DCHECK(task_source);
540 new_thread_group->PushTaskSourceAndWakeUpWorkers(
541 {std::move(registered_task_source), std::move(transaction)});
542 }
543 }
544 }
545
UpdateJobPriority(scoped_refptr<TaskSource> task_source,TaskPriority priority)546 void ThreadPoolImpl::UpdateJobPriority(scoped_refptr<TaskSource> task_source,
547 TaskPriority priority) {
548 UpdatePriority(std::move(task_source), priority);
549 }
550
GetThreadGroupForTraits(const TaskTraits & traits) const551 const ThreadGroup* ThreadPoolImpl::GetThreadGroupForTraits(
552 const TaskTraits& traits) const {
553 return const_cast<ThreadPoolImpl*>(this)->GetThreadGroupForTraits(traits);
554 }
555
GetThreadGroupForTraits(const TaskTraits & traits)556 ThreadGroup* ThreadPoolImpl::GetThreadGroupForTraits(const TaskTraits& traits) {
557 if (traits.priority() == TaskPriority::BEST_EFFORT &&
558 traits.thread_policy() == ThreadPolicy::PREFER_BACKGROUND &&
559 background_thread_group_) {
560 return background_thread_group_.get();
561 }
562
563 if (traits.priority() <= TaskPriority::USER_VISIBLE &&
564 traits.thread_policy() == ThreadPolicy::PREFER_BACKGROUND &&
565 utility_thread_group_) {
566 return utility_thread_group_.get();
567 }
568
569 return foreground_thread_group_.get();
570 }
571
UpdateCanRunPolicy()572 void ThreadPoolImpl::UpdateCanRunPolicy() {
573 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
574
575 CanRunPolicy can_run_policy;
576 if ((num_fences_ == 0 && num_best_effort_fences_ == 0 &&
577 !has_disable_best_effort_switch_) ||
578 task_tracker_->HasShutdownStarted()) {
579 can_run_policy = CanRunPolicy::kAll;
580 } else if (num_fences_ != 0) {
581 can_run_policy = CanRunPolicy::kNone;
582 } else {
583 DCHECK(num_best_effort_fences_ > 0 || has_disable_best_effort_switch_);
584 can_run_policy = CanRunPolicy::kForegroundOnly;
585 }
586
587 task_tracker_->SetCanRunPolicy(can_run_policy);
588 foreground_thread_group_->DidUpdateCanRunPolicy();
589 if (utility_thread_group_)
590 utility_thread_group_->DidUpdateCanRunPolicy();
591 if (background_thread_group_)
592 background_thread_group_->DidUpdateCanRunPolicy();
593 single_thread_task_runner_manager_.DidUpdateCanRunPolicy();
594 }
595
596 } // namespace internal
597 } // namespace base
598