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