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