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