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