• 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 <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