xref: /aosp_15_r20/external/cronet/base/task/post_job.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/task/post_job.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include "base/task/scoped_set_task_priority_for_current_thread.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/job_task_source.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/pooled_task_runner_delegate.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/thread_pool_impl.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool/thread_pool_instance.h"
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker namespace base {
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker namespace {
16*6777b538SAndroid Build Coastguard Worker 
CreateJobTaskSource(const Location & from_here,const TaskTraits & traits,RepeatingCallback<void (JobDelegate *)> worker_task,MaxConcurrencyCallback max_concurrency_callback)17*6777b538SAndroid Build Coastguard Worker scoped_refptr<internal::JobTaskSource> CreateJobTaskSource(
18*6777b538SAndroid Build Coastguard Worker     const Location& from_here,
19*6777b538SAndroid Build Coastguard Worker     const TaskTraits& traits,
20*6777b538SAndroid Build Coastguard Worker     RepeatingCallback<void(JobDelegate*)> worker_task,
21*6777b538SAndroid Build Coastguard Worker     MaxConcurrencyCallback max_concurrency_callback) {
22*6777b538SAndroid Build Coastguard Worker   DCHECK(ThreadPoolInstance::Get())
23*6777b538SAndroid Build Coastguard Worker       << "Hint: if this is in a unit test, you're likely merely missing a "
24*6777b538SAndroid Build Coastguard Worker          "base::test::TaskEnvironment member in your fixture.\n";
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker   return base::MakeRefCounted<internal::JobTaskSource>(
27*6777b538SAndroid Build Coastguard Worker       from_here, traits, std::move(worker_task),
28*6777b538SAndroid Build Coastguard Worker       std::move(max_concurrency_callback),
29*6777b538SAndroid Build Coastguard Worker       static_cast<internal::ThreadPoolImpl*>(ThreadPoolInstance::Get()));
30*6777b538SAndroid Build Coastguard Worker }
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker }  // namespace
33*6777b538SAndroid Build Coastguard Worker 
JobDelegate(internal::JobTaskSource * task_source,internal::PooledTaskRunnerDelegate * pooled_task_runner_delegate)34*6777b538SAndroid Build Coastguard Worker JobDelegate::JobDelegate(
35*6777b538SAndroid Build Coastguard Worker     internal::JobTaskSource* task_source,
36*6777b538SAndroid Build Coastguard Worker     internal::PooledTaskRunnerDelegate* pooled_task_runner_delegate)
37*6777b538SAndroid Build Coastguard Worker     : task_source_(task_source),
38*6777b538SAndroid Build Coastguard Worker       pooled_task_runner_delegate_(pooled_task_runner_delegate) {
39*6777b538SAndroid Build Coastguard Worker   DCHECK(task_source_);
40*6777b538SAndroid Build Coastguard Worker }
41*6777b538SAndroid Build Coastguard Worker 
~JobDelegate()42*6777b538SAndroid Build Coastguard Worker JobDelegate::~JobDelegate() {
43*6777b538SAndroid Build Coastguard Worker   if (task_id_ != kInvalidTaskId)
44*6777b538SAndroid Build Coastguard Worker     task_source_->ReleaseTaskId(task_id_);
45*6777b538SAndroid Build Coastguard Worker }
46*6777b538SAndroid Build Coastguard Worker 
ShouldYield()47*6777b538SAndroid Build Coastguard Worker bool JobDelegate::ShouldYield() {
48*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
49*6777b538SAndroid Build Coastguard Worker   // ShouldYield() shouldn't be called again after returning true.
50*6777b538SAndroid Build Coastguard Worker   DCHECK(!last_should_yield_);
51*6777b538SAndroid Build Coastguard Worker #endif  // DCHECK_IS_ON()
52*6777b538SAndroid Build Coastguard Worker   const bool should_yield =
53*6777b538SAndroid Build Coastguard Worker       task_source_->ShouldYield() ||
54*6777b538SAndroid Build Coastguard Worker       (pooled_task_runner_delegate_ &&
55*6777b538SAndroid Build Coastguard Worker        pooled_task_runner_delegate_->ShouldYield(task_source_));
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
58*6777b538SAndroid Build Coastguard Worker   last_should_yield_ = should_yield;
59*6777b538SAndroid Build Coastguard Worker #endif  // DCHECK_IS_ON()
60*6777b538SAndroid Build Coastguard Worker   return should_yield;
61*6777b538SAndroid Build Coastguard Worker }
62*6777b538SAndroid Build Coastguard Worker 
YieldIfNeeded()63*6777b538SAndroid Build Coastguard Worker void JobDelegate::YieldIfNeeded() {
64*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/839091): Implement this.
65*6777b538SAndroid Build Coastguard Worker }
66*6777b538SAndroid Build Coastguard Worker 
NotifyConcurrencyIncrease()67*6777b538SAndroid Build Coastguard Worker void JobDelegate::NotifyConcurrencyIncrease() {
68*6777b538SAndroid Build Coastguard Worker   task_source_->NotifyConcurrencyIncrease();
69*6777b538SAndroid Build Coastguard Worker }
70*6777b538SAndroid Build Coastguard Worker 
GetTaskId()71*6777b538SAndroid Build Coastguard Worker uint8_t JobDelegate::GetTaskId() {
72*6777b538SAndroid Build Coastguard Worker   if (task_id_ == kInvalidTaskId)
73*6777b538SAndroid Build Coastguard Worker     task_id_ = task_source_->AcquireTaskId();
74*6777b538SAndroid Build Coastguard Worker   return task_id_;
75*6777b538SAndroid Build Coastguard Worker }
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker JobHandle::JobHandle() = default;
78*6777b538SAndroid Build Coastguard Worker 
JobHandle(scoped_refptr<internal::JobTaskSource> task_source)79*6777b538SAndroid Build Coastguard Worker JobHandle::JobHandle(scoped_refptr<internal::JobTaskSource> task_source)
80*6777b538SAndroid Build Coastguard Worker     : task_source_(std::move(task_source)) {}
81*6777b538SAndroid Build Coastguard Worker 
~JobHandle()82*6777b538SAndroid Build Coastguard Worker JobHandle::~JobHandle() {
83*6777b538SAndroid Build Coastguard Worker   DCHECK(!task_source_)
84*6777b538SAndroid Build Coastguard Worker       << "The Job must be cancelled, detached or joined before its "
85*6777b538SAndroid Build Coastguard Worker          "JobHandle is destroyed.";
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker JobHandle::JobHandle(JobHandle&&) = default;
89*6777b538SAndroid Build Coastguard Worker 
operator =(JobHandle && other)90*6777b538SAndroid Build Coastguard Worker JobHandle& JobHandle::operator=(JobHandle&& other) {
91*6777b538SAndroid Build Coastguard Worker   DCHECK(!task_source_)
92*6777b538SAndroid Build Coastguard Worker       << "The Job must be cancelled, detached or joined before its "
93*6777b538SAndroid Build Coastguard Worker          "JobHandle is re-assigned.";
94*6777b538SAndroid Build Coastguard Worker   task_source_ = std::move(other.task_source_);
95*6777b538SAndroid Build Coastguard Worker   return *this;
96*6777b538SAndroid Build Coastguard Worker }
97*6777b538SAndroid Build Coastguard Worker 
IsActive() const98*6777b538SAndroid Build Coastguard Worker bool JobHandle::IsActive() const {
99*6777b538SAndroid Build Coastguard Worker   return task_source_->IsActive();
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker 
UpdatePriority(TaskPriority new_priority)102*6777b538SAndroid Build Coastguard Worker void JobHandle::UpdatePriority(TaskPriority new_priority) {
103*6777b538SAndroid Build Coastguard Worker   if (!internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
104*6777b538SAndroid Build Coastguard Worker           task_source_->delegate())) {
105*6777b538SAndroid Build Coastguard Worker     return;
106*6777b538SAndroid Build Coastguard Worker   }
107*6777b538SAndroid Build Coastguard Worker   task_source_->delegate()->UpdateJobPriority(task_source_, new_priority);
108*6777b538SAndroid Build Coastguard Worker }
109*6777b538SAndroid Build Coastguard Worker 
NotifyConcurrencyIncrease()110*6777b538SAndroid Build Coastguard Worker void JobHandle::NotifyConcurrencyIncrease() {
111*6777b538SAndroid Build Coastguard Worker   if (!internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
112*6777b538SAndroid Build Coastguard Worker           task_source_->delegate())) {
113*6777b538SAndroid Build Coastguard Worker     return;
114*6777b538SAndroid Build Coastguard Worker   }
115*6777b538SAndroid Build Coastguard Worker   task_source_->NotifyConcurrencyIncrease();
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker 
Join()118*6777b538SAndroid Build Coastguard Worker void JobHandle::Join() {
119*6777b538SAndroid Build Coastguard Worker   DCHECK(internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
120*6777b538SAndroid Build Coastguard Worker       task_source_->delegate()));
121*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(internal::GetTaskPriorityForCurrentThread(),
122*6777b538SAndroid Build Coastguard Worker             task_source_->priority_racy())
123*6777b538SAndroid Build Coastguard Worker       << "Join may not be called on Job with higher priority than the current "
124*6777b538SAndroid Build Coastguard Worker          "thread.";
125*6777b538SAndroid Build Coastguard Worker   UpdatePriority(internal::GetTaskPriorityForCurrentThread());
126*6777b538SAndroid Build Coastguard Worker   if (task_source_->GetRemainingConcurrency() != 0) {
127*6777b538SAndroid Build Coastguard Worker     // Make sure the task source is in the queue if not enough workers are
128*6777b538SAndroid Build Coastguard Worker     // contributing. This is necessary for CreateJob(...).Join(). This is a
129*6777b538SAndroid Build Coastguard Worker     // noop if the task source was already in the queue.
130*6777b538SAndroid Build Coastguard Worker     task_source_->delegate()->EnqueueJobTaskSource(task_source_);
131*6777b538SAndroid Build Coastguard Worker   }
132*6777b538SAndroid Build Coastguard Worker   bool must_run = task_source_->WillJoin();
133*6777b538SAndroid Build Coastguard Worker   while (must_run)
134*6777b538SAndroid Build Coastguard Worker     must_run = task_source_->RunJoinTask();
135*6777b538SAndroid Build Coastguard Worker   // Remove |task_source_| from the ThreadPool to prevent access to
136*6777b538SAndroid Build Coastguard Worker   // |max_concurrency_callback| after Join().
137*6777b538SAndroid Build Coastguard Worker   task_source_->delegate()->RemoveJobTaskSource(task_source_);
138*6777b538SAndroid Build Coastguard Worker   task_source_ = nullptr;
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker 
Cancel()141*6777b538SAndroid Build Coastguard Worker void JobHandle::Cancel() {
142*6777b538SAndroid Build Coastguard Worker   DCHECK(internal::PooledTaskRunnerDelegate::MatchesCurrentDelegate(
143*6777b538SAndroid Build Coastguard Worker       task_source_->delegate()));
144*6777b538SAndroid Build Coastguard Worker   task_source_->Cancel();
145*6777b538SAndroid Build Coastguard Worker   bool must_run = task_source_->WillJoin();
146*6777b538SAndroid Build Coastguard Worker   DCHECK(!must_run);
147*6777b538SAndroid Build Coastguard Worker   // Remove |task_source_| from the ThreadPool to prevent access to
148*6777b538SAndroid Build Coastguard Worker   // |max_concurrency_callback| after Join().
149*6777b538SAndroid Build Coastguard Worker   task_source_->delegate()->RemoveJobTaskSource(task_source_);
150*6777b538SAndroid Build Coastguard Worker   task_source_ = nullptr;
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker 
CancelAndDetach()153*6777b538SAndroid Build Coastguard Worker void JobHandle::CancelAndDetach() {
154*6777b538SAndroid Build Coastguard Worker   task_source_->Cancel();
155*6777b538SAndroid Build Coastguard Worker   Detach();
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker 
Detach()158*6777b538SAndroid Build Coastguard Worker void JobHandle::Detach() {
159*6777b538SAndroid Build Coastguard Worker   DCHECK(task_source_);
160*6777b538SAndroid Build Coastguard Worker   task_source_ = nullptr;
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker 
PostJob(const Location & from_here,const TaskTraits & traits,RepeatingCallback<void (JobDelegate *)> worker_task,MaxConcurrencyCallback max_concurrency_callback)163*6777b538SAndroid Build Coastguard Worker JobHandle PostJob(const Location& from_here,
164*6777b538SAndroid Build Coastguard Worker                   const TaskTraits& traits,
165*6777b538SAndroid Build Coastguard Worker                   RepeatingCallback<void(JobDelegate*)> worker_task,
166*6777b538SAndroid Build Coastguard Worker                   MaxConcurrencyCallback max_concurrency_callback) {
167*6777b538SAndroid Build Coastguard Worker   auto task_source =
168*6777b538SAndroid Build Coastguard Worker       CreateJobTaskSource(from_here, traits, std::move(worker_task),
169*6777b538SAndroid Build Coastguard Worker                           std::move(max_concurrency_callback));
170*6777b538SAndroid Build Coastguard Worker   const bool queued =
171*6777b538SAndroid Build Coastguard Worker       static_cast<internal::ThreadPoolImpl*>(ThreadPoolInstance::Get())
172*6777b538SAndroid Build Coastguard Worker           ->EnqueueJobTaskSource(task_source);
173*6777b538SAndroid Build Coastguard Worker   if (queued) {
174*6777b538SAndroid Build Coastguard Worker     return internal::JobTaskSource::CreateJobHandle(std::move(task_source));
175*6777b538SAndroid Build Coastguard Worker   }
176*6777b538SAndroid Build Coastguard Worker   return JobHandle();
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker 
CreateJob(const Location & from_here,const TaskTraits & traits,RepeatingCallback<void (JobDelegate *)> worker_task,MaxConcurrencyCallback max_concurrency_callback)179*6777b538SAndroid Build Coastguard Worker JobHandle CreateJob(const Location& from_here,
180*6777b538SAndroid Build Coastguard Worker                     const TaskTraits& traits,
181*6777b538SAndroid Build Coastguard Worker                     RepeatingCallback<void(JobDelegate*)> worker_task,
182*6777b538SAndroid Build Coastguard Worker                     MaxConcurrencyCallback max_concurrency_callback) {
183*6777b538SAndroid Build Coastguard Worker   auto task_source =
184*6777b538SAndroid Build Coastguard Worker       CreateJobTaskSource(from_here, traits, std::move(worker_task),
185*6777b538SAndroid Build Coastguard Worker                           std::move(max_concurrency_callback));
186*6777b538SAndroid Build Coastguard Worker   return internal::JobTaskSource::CreateJobHandle(std::move(task_source));
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker }  // namespace base
190