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