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