xref: /aosp_15_r20/external/cronet/base/task/thread_pool/task_source.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 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/task_source.h"
6 
7 #include <utility>
8 
9 #include "base/check_op.h"
10 #include "base/feature_list.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/task/task_features.h"
13 #include "base/task/thread_pool/task_tracker.h"
14 
15 namespace base {
16 namespace internal {
17 
18 ExecutionEnvironment::~ExecutionEnvironment() = default;
19 
Transaction(TaskSource * task_source)20 TaskSource::Transaction::Transaction(TaskSource* task_source)
21     : task_source_(task_source) {
22   task_source->lock_.Acquire();
23 }
24 
Transaction(TaskSource::Transaction && other)25 TaskSource::Transaction::Transaction(TaskSource::Transaction&& other)
26     : task_source_(other.task_source()) {
27   other.task_source_ = nullptr;
28 }
29 
~Transaction()30 TaskSource::Transaction::~Transaction() {
31   if (task_source_) {
32     Release();
33   }
34 }
35 
UpdatePriority(TaskPriority priority)36 void TaskSource::Transaction::UpdatePriority(TaskPriority priority) {
37   task_source_->traits_.UpdatePriority(priority);
38   task_source_->priority_racy_.store(task_source_->traits_.priority(),
39                                      std::memory_order_relaxed);
40 }
41 
Release()42 void TaskSource::Transaction::Release() NO_THREAD_SAFETY_ANALYSIS {
43   DCHECK(task_source_);
44   task_source_->lock_.AssertAcquired();
45   task_source_->lock_.Release();
46   task_source_ = nullptr;
47 }
48 
SetImmediateHeapHandle(const HeapHandle & handle)49 void TaskSource::SetImmediateHeapHandle(const HeapHandle& handle) {
50   immediate_pq_heap_handle_ = handle;
51 }
52 
ClearImmediateHeapHandle()53 void TaskSource::ClearImmediateHeapHandle() {
54   immediate_pq_heap_handle_ = HeapHandle();
55 }
56 
SetDelayedHeapHandle(const HeapHandle & handle)57 void TaskSource::SetDelayedHeapHandle(const HeapHandle& handle) {
58   delayed_pq_heap_handle_ = handle;
59 }
60 
ClearDelayedHeapHandle()61 void TaskSource::ClearDelayedHeapHandle() {
62   delayed_pq_heap_handle_ = HeapHandle();
63 }
64 
TaskSource(const TaskTraits & traits,TaskSourceExecutionMode execution_mode)65 TaskSource::TaskSource(const TaskTraits& traits,
66                        TaskSourceExecutionMode execution_mode)
67     : traits_(traits),
68       priority_racy_(traits.priority()),
69       execution_mode_(execution_mode) {}
70 
~TaskSource()71 TaskSource::~TaskSource() {
72   // If this fails, a Transaction was likely held while releasing a reference to
73   // its associated task source, which lead to its destruction. Owners of
74   // Transaction must ensure to hold onto a reference of the associated task
75   // source at least until the Transaction is released to prevent UAF.
76   lock_.AssertNotHeld();
77 }
78 
BeginTransaction()79 TaskSource::Transaction TaskSource::BeginTransaction() {
80   return Transaction(this);
81 }
82 
ClearForTesting()83 void TaskSource::ClearForTesting() {
84   auto task = Clear(nullptr);
85   if (task) {
86     std::move(task->task).Run();
87   }
88 }
89 
90 RegisteredTaskSource::RegisteredTaskSource() = default;
91 
RegisteredTaskSource(std::nullptr_t)92 RegisteredTaskSource::RegisteredTaskSource(std::nullptr_t)
93     : RegisteredTaskSource() {}
94 
RegisteredTaskSource(RegisteredTaskSource && other)95 RegisteredTaskSource::RegisteredTaskSource(
96     RegisteredTaskSource&& other) noexcept
97     :
98 #if DCHECK_IS_ON()
99       run_step_{std::exchange(other.run_step_, State::kInitial)},
100 #endif  // DCHECK_IS_ON()
101       task_source_{std::move(other.task_source_)},
102       task_tracker_{std::exchange(other.task_tracker_, nullptr)} {
103 }
104 
~RegisteredTaskSource()105 RegisteredTaskSource::~RegisteredTaskSource() {
106   Unregister();
107 }
108 
109 //  static
CreateForTesting(scoped_refptr<TaskSource> task_source,TaskTracker * task_tracker)110 RegisteredTaskSource RegisteredTaskSource::CreateForTesting(
111     scoped_refptr<TaskSource> task_source,
112     TaskTracker* task_tracker) {
113   return RegisteredTaskSource(std::move(task_source), task_tracker);
114 }
115 
Unregister()116 scoped_refptr<TaskSource> RegisteredTaskSource::Unregister() {
117 #if DCHECK_IS_ON()
118   DCHECK_EQ(run_step_, State::kInitial);
119 #endif  // DCHECK_IS_ON()
120   if (task_source_ && task_tracker_)
121     return task_tracker_->UnregisterTaskSource(std::move(task_source_));
122   return std::move(task_source_);
123 }
124 
operator =(RegisteredTaskSource && other)125 RegisteredTaskSource& RegisteredTaskSource::operator=(
126     RegisteredTaskSource&& other) {
127   Unregister();
128 #if DCHECK_IS_ON()
129   run_step_ = std::exchange(other.run_step_, State::kInitial);
130 #endif  // DCHECK_IS_ON()
131   task_source_ = std::move(other.task_source_);
132   task_tracker_ = std::exchange(other.task_tracker_, nullptr);
133   return *this;
134 }
135 
WillRunTask()136 TaskSource::RunStatus RegisteredTaskSource::WillRunTask() {
137   TaskSource::RunStatus run_status = task_source_->WillRunTask();
138 #if DCHECK_IS_ON()
139   DCHECK_EQ(run_step_, State::kInitial);
140   if (run_status != TaskSource::RunStatus::kDisallowed)
141     run_step_ = State::kReady;
142 #endif  // DCHECK_IS_ON()
143   return run_status;
144 }
145 
TakeTask(TaskSource::Transaction * transaction)146 Task RegisteredTaskSource::TakeTask(TaskSource::Transaction* transaction) {
147   DCHECK(!transaction || transaction->task_source() == get());
148 #if DCHECK_IS_ON()
149   DCHECK_EQ(State::kReady, run_step_);
150 #endif  // DCHECK_IS_ON()
151   return task_source_->TakeTask(transaction);
152 }
153 
Clear(TaskSource::Transaction * transaction)154 std::optional<Task> RegisteredTaskSource::Clear(
155     TaskSource::Transaction* transaction) {
156   DCHECK(!transaction || transaction->task_source() == get());
157   return task_source_->Clear(transaction);
158 }
159 
DidProcessTask(TaskSource::Transaction * transaction)160 bool RegisteredTaskSource::DidProcessTask(
161     TaskSource::Transaction* transaction) {
162   DCHECK(!transaction || transaction->task_source() == get());
163 #if DCHECK_IS_ON()
164   DCHECK_EQ(State::kReady, run_step_);
165   run_step_ = State::kInitial;
166 #endif  // DCHECK_IS_ON()
167   return task_source_->DidProcessTask(transaction);
168 }
169 
WillReEnqueue(TimeTicks now,TaskSource::Transaction * transaction)170 bool RegisteredTaskSource::WillReEnqueue(TimeTicks now,
171                                          TaskSource::Transaction* transaction) {
172   DCHECK(!transaction || transaction->task_source() == get());
173 #if DCHECK_IS_ON()
174   DCHECK_EQ(State::kInitial, run_step_);
175 #endif  // DCHECK_IS_ON()
176   return task_source_->WillReEnqueue(now, transaction);
177 }
178 
RegisteredTaskSource(scoped_refptr<TaskSource> task_source,TaskTracker * task_tracker)179 RegisteredTaskSource::RegisteredTaskSource(
180     scoped_refptr<TaskSource> task_source,
181     TaskTracker* task_tracker)
182     : task_source_(std::move(task_source)), task_tracker_(task_tracker) {}
183 
RegisteredTaskSourceAndTransaction(RegisteredTaskSource task_source_in,TaskSource::Transaction transaction_in)184 RegisteredTaskSourceAndTransaction::RegisteredTaskSourceAndTransaction(
185     RegisteredTaskSource task_source_in,
186     TaskSource::Transaction transaction_in)
187     : task_source(std::move(task_source_in)),
188       transaction(std::move(transaction_in)) {
189   DCHECK_EQ(task_source.get(), transaction.task_source());
190 }
191 
192 // static:
193 RegisteredTaskSourceAndTransaction
FromTaskSource(RegisteredTaskSource task_source_in)194 RegisteredTaskSourceAndTransaction::FromTaskSource(
195     RegisteredTaskSource task_source_in) {
196   auto transaction = task_source_in->BeginTransaction();
197   return RegisteredTaskSourceAndTransaction(std::move(task_source_in),
198                                             std::move(transaction));
199 }
200 
201 TaskSourceAndTransaction::TaskSourceAndTransaction(
202     TaskSourceAndTransaction&& other) = default;
203 
204 TaskSourceAndTransaction::~TaskSourceAndTransaction() = default;
205 
TaskSourceAndTransaction(scoped_refptr<TaskSource> task_source_in,TaskSource::Transaction transaction_in)206 TaskSourceAndTransaction::TaskSourceAndTransaction(
207     scoped_refptr<TaskSource> task_source_in,
208     TaskSource::Transaction transaction_in)
209     : task_source(std::move(task_source_in)),
210       transaction(std::move(transaction_in)) {
211   DCHECK_EQ(task_source.get(), transaction.task_source());
212 }
213 
214 // static:
FromTaskSource(scoped_refptr<TaskSource> task_source_in)215 TaskSourceAndTransaction TaskSourceAndTransaction::FromTaskSource(
216     scoped_refptr<TaskSource> task_source_in) {
217   auto transaction = task_source_in->BeginTransaction();
218   return TaskSourceAndTransaction(std::move(task_source_in),
219                                   std::move(transaction));
220 }
221 
222 }  // namespace internal
223 }  // namespace base
224