1 // Copyright 2017 The Chromium Authors. All rights reserved.
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/sequence_manager/task_queue.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/task/sequence_manager/associated_thread_id.h"
12 #include "base/task/sequence_manager/sequence_manager_impl.h"
13 #include "base/task/sequence_manager/task_queue_impl.h"
14 #include "base/threading/thread_checker.h"
15 #include "base/threading/thread_checker_impl.h"
16 #include "base/time/time.h"
17
18 namespace base {
19 namespace sequence_manager {
20
21 namespace {
22
23 class NullTaskRunner final : public SingleThreadTaskRunner {
24 public:
NullTaskRunner()25 NullTaskRunner() {}
26
PostDelayedTask(const Location & location,OnceClosure callback,TimeDelta delay)27 bool PostDelayedTask(const Location& location,
28 OnceClosure callback,
29 TimeDelta delay) override {
30 return false;
31 }
32
PostNonNestableDelayedTask(const Location & location,OnceClosure callback,TimeDelta delay)33 bool PostNonNestableDelayedTask(const Location& location,
34 OnceClosure callback,
35 TimeDelta delay) override {
36 return false;
37 }
38
RunsTasksInCurrentSequence() const39 bool RunsTasksInCurrentSequence() const override {
40 return thread_checker_.CalledOnValidThread();
41 }
42
43 private:
44 // Ref-counted
45 ~NullTaskRunner() override = default;
46
47 ThreadCheckerImpl thread_checker_;
48 };
49
50 // TODO(kraynov): Move NullTaskRunner from //base/test to //base.
CreateNullTaskRunner()51 scoped_refptr<SingleThreadTaskRunner> CreateNullTaskRunner() {
52 return MakeRefCounted<NullTaskRunner>();
53 }
54
55 } // namespace
56
QueueEnabledVoter(scoped_refptr<TaskQueue> task_queue)57 TaskQueue::QueueEnabledVoter::QueueEnabledVoter(
58 scoped_refptr<TaskQueue> task_queue)
59 : task_queue_(std::move(task_queue)), enabled_(true) {
60 task_queue_->AddQueueEnabledVoter(enabled_);
61 }
62
~QueueEnabledVoter()63 TaskQueue::QueueEnabledVoter::~QueueEnabledVoter() {
64 task_queue_->RemoveQueueEnabledVoter(enabled_);
65 }
66
SetVoteToEnable(bool enabled)67 void TaskQueue::QueueEnabledVoter::SetVoteToEnable(bool enabled) {
68 if (enabled == enabled_)
69 return;
70 enabled_ = enabled;
71 task_queue_->OnQueueEnabledVoteChanged(enabled_);
72 }
73
AddQueueEnabledVoter(bool voter_is_enabled)74 void TaskQueue::AddQueueEnabledVoter(bool voter_is_enabled) {
75 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
76 ++voter_count_;
77 if (voter_is_enabled)
78 ++enabled_voter_count_;
79 }
80
RemoveQueueEnabledVoter(bool voter_is_enabled)81 void TaskQueue::RemoveQueueEnabledVoter(bool voter_is_enabled) {
82 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
83 if (!impl_)
84 return;
85
86 bool was_enabled = AreAllQueueEnabledVotersEnabled();
87 if (voter_is_enabled) {
88 --enabled_voter_count_;
89 DCHECK_GE(enabled_voter_count_, 0);
90 }
91
92 --voter_count_;
93 DCHECK_GE(voter_count_, 0);
94
95 bool is_enabled = AreAllQueueEnabledVotersEnabled();
96 if (was_enabled != is_enabled)
97 impl_->SetQueueEnabled(is_enabled);
98 }
99
AreAllQueueEnabledVotersEnabled() const100 bool TaskQueue::AreAllQueueEnabledVotersEnabled() const {
101 return enabled_voter_count_ == voter_count_;
102 }
103
OnQueueEnabledVoteChanged(bool enabled)104 void TaskQueue::OnQueueEnabledVoteChanged(bool enabled) {
105 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
106 bool was_enabled = AreAllQueueEnabledVotersEnabled();
107 if (enabled) {
108 ++enabled_voter_count_;
109 DCHECK_LE(enabled_voter_count_, voter_count_);
110 } else {
111 --enabled_voter_count_;
112 DCHECK_GE(enabled_voter_count_, 0);
113 }
114
115 bool is_enabled = AreAllQueueEnabledVotersEnabled();
116 if (was_enabled != is_enabled)
117 impl_->SetQueueEnabled(is_enabled);
118 }
119
TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,const TaskQueue::Spec & spec)120 TaskQueue::TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,
121 const TaskQueue::Spec& spec)
122 : impl_(std::move(impl)),
123 sequence_manager_(impl_ ? impl_->GetSequenceManagerWeakPtr() : nullptr),
124 associated_thread_((impl_ && impl_->sequence_manager())
125 ? impl_->sequence_manager()->associated_thread()
126 : MakeRefCounted<internal::AssociatedThreadId>()),
127 default_task_runner_(impl_ ? impl_->CreateTaskRunner(kTaskTypeNone)
128 : CreateNullTaskRunner()),
129 name_(impl_ ? impl_->GetName() : "") {}
130
~TaskQueue()131 TaskQueue::~TaskQueue() {
132 ShutdownTaskQueueGracefully();
133 }
134
ShutdownTaskQueueGracefully()135 void TaskQueue::ShutdownTaskQueueGracefully() {
136 // scoped_refptr guarantees us that this object isn't used.
137 if (!impl_)
138 return;
139 if (impl_->IsUnregistered())
140 return;
141
142 // If we've not been unregistered then this must occur on the main thread.
143 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
144 impl_->SetObserver(nullptr);
145 if (auto* sequence_manager = impl_->sequence_manager())
146 sequence_manager->ShutdownTaskQueueGracefully(TakeTaskQueueImpl());
147 }
148
TaskTiming(bool has_wall_time,bool has_thread_time)149 TaskQueue::TaskTiming::TaskTiming(bool has_wall_time, bool has_thread_time)
150 : has_wall_time_(has_wall_time), has_thread_time_(has_thread_time) {}
151
RecordTaskStart(LazyNow * now)152 void TaskQueue::TaskTiming::RecordTaskStart(LazyNow* now) {
153 DCHECK_EQ(State::NotStarted, state_);
154 state_ = State::Running;
155
156 if (has_wall_time())
157 start_time_ = now->Now();
158 if (has_thread_time())
159 start_thread_time_ = base::ThreadTicks::Now();
160 }
161
RecordTaskEnd(LazyNow * now)162 void TaskQueue::TaskTiming::RecordTaskEnd(LazyNow* now) {
163 DCHECK(state_ == State::Running || state_ == State::Finished);
164 if (state_ == State::Finished)
165 return;
166 state_ = State::Finished;
167
168 if (has_wall_time())
169 end_time_ = now->Now();
170 if (has_thread_time())
171 end_thread_time_ = base::ThreadTicks::Now();
172 }
173
ShutdownTaskQueue()174 void TaskQueue::ShutdownTaskQueue() {
175 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
176 if (!impl_)
177 return;
178 if (!sequence_manager_) {
179 TakeTaskQueueImpl().reset();
180 return;
181 }
182 impl_->SetBlameContext(nullptr);
183 impl_->SetOnTaskStartedHandler(
184 internal::TaskQueueImpl::OnTaskStartedHandler());
185 impl_->SetOnTaskCompletedHandler(
186 internal::TaskQueueImpl::OnTaskCompletedHandler());
187 sequence_manager_->UnregisterTaskQueueImpl(TakeTaskQueueImpl());
188 }
189
CreateTaskRunner(TaskType task_type)190 scoped_refptr<SingleThreadTaskRunner> TaskQueue::CreateTaskRunner(
191 TaskType task_type) {
192 // We only need to lock if we're not on the main thread.
193 base::internal::CheckedAutoLockMaybe lock(IsOnMainThread() ? &impl_lock_
194 : nullptr);
195 if (!impl_)
196 return CreateNullTaskRunner();
197 return impl_->CreateTaskRunner(task_type);
198 }
199
200 std::unique_ptr<TaskQueue::QueueEnabledVoter>
CreateQueueEnabledVoter()201 TaskQueue::CreateQueueEnabledVoter() {
202 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
203 if (!impl_)
204 return nullptr;
205 return WrapUnique(new QueueEnabledVoter(this));
206 }
207
IsQueueEnabled() const208 bool TaskQueue::IsQueueEnabled() const {
209 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
210 if (!impl_)
211 return false;
212 return impl_->IsQueueEnabled();
213 }
214
IsEmpty() const215 bool TaskQueue::IsEmpty() const {
216 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
217 if (!impl_)
218 return true;
219 return impl_->IsEmpty();
220 }
221
GetNumberOfPendingTasks() const222 size_t TaskQueue::GetNumberOfPendingTasks() const {
223 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
224 if (!impl_)
225 return 0;
226 return impl_->GetNumberOfPendingTasks();
227 }
228
HasTaskToRunImmediately() const229 bool TaskQueue::HasTaskToRunImmediately() const {
230 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
231 if (!impl_)
232 return false;
233 return impl_->HasTaskToRunImmediately();
234 }
235
GetNextScheduledWakeUp()236 Optional<TimeTicks> TaskQueue::GetNextScheduledWakeUp() {
237 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
238 if (!impl_)
239 return nullopt;
240 return impl_->GetNextScheduledWakeUp();
241 }
242
SetQueuePriority(TaskQueue::QueuePriority priority)243 void TaskQueue::SetQueuePriority(TaskQueue::QueuePriority priority) {
244 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
245 if (!impl_)
246 return;
247 impl_->SetQueuePriority(priority);
248 }
249
GetQueuePriority() const250 TaskQueue::QueuePriority TaskQueue::GetQueuePriority() const {
251 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
252 if (!impl_)
253 return TaskQueue::QueuePriority::kLowPriority;
254 return impl_->GetQueuePriority();
255 }
256
AddTaskObserver(TaskObserver * task_observer)257 void TaskQueue::AddTaskObserver(TaskObserver* task_observer) {
258 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
259 if (!impl_)
260 return;
261 impl_->AddTaskObserver(task_observer);
262 }
263
RemoveTaskObserver(TaskObserver * task_observer)264 void TaskQueue::RemoveTaskObserver(TaskObserver* task_observer) {
265 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
266 if (!impl_)
267 return;
268 impl_->RemoveTaskObserver(task_observer);
269 }
270
SetTimeDomain(TimeDomain * time_domain)271 void TaskQueue::SetTimeDomain(TimeDomain* time_domain) {
272 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
273 if (!impl_)
274 return;
275 impl_->SetTimeDomain(time_domain);
276 }
277
GetTimeDomain() const278 TimeDomain* TaskQueue::GetTimeDomain() const {
279 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
280 if (!impl_)
281 return nullptr;
282 return impl_->GetTimeDomain();
283 }
284
SetBlameContext(trace_event::BlameContext * blame_context)285 void TaskQueue::SetBlameContext(trace_event::BlameContext* blame_context) {
286 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
287 if (!impl_)
288 return;
289 impl_->SetBlameContext(blame_context);
290 }
291
InsertFence(InsertFencePosition position)292 void TaskQueue::InsertFence(InsertFencePosition position) {
293 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
294 if (!impl_)
295 return;
296 impl_->InsertFence(position);
297 }
298
InsertFenceAt(TimeTicks time)299 void TaskQueue::InsertFenceAt(TimeTicks time) {
300 impl_->InsertFenceAt(time);
301 }
302
RemoveFence()303 void TaskQueue::RemoveFence() {
304 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
305 if (!impl_)
306 return;
307 impl_->RemoveFence();
308 }
309
HasActiveFence()310 bool TaskQueue::HasActiveFence() {
311 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
312 if (!impl_)
313 return false;
314 return impl_->HasActiveFence();
315 }
316
BlockedByFence() const317 bool TaskQueue::BlockedByFence() const {
318 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
319 if (!impl_)
320 return false;
321 return impl_->BlockedByFence();
322 }
323
GetEnqueueOrderAtWhichWeBecameUnblocked() const324 EnqueueOrder TaskQueue::GetEnqueueOrderAtWhichWeBecameUnblocked() const {
325 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
326 if (!impl_)
327 return EnqueueOrder();
328 return impl_->GetEnqueueOrderAtWhichWeBecameUnblocked();
329 }
330
GetName() const331 const char* TaskQueue::GetName() const {
332 return name_;
333 }
334
SetObserver(Observer * observer)335 void TaskQueue::SetObserver(Observer* observer) {
336 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
337 if (!impl_)
338 return;
339
340 // Observer is guaranteed to outlive TaskQueue and TaskQueueImpl lifecycle is
341 // controlled by |this|.
342 impl_->SetObserver(observer);
343 }
344
SetShouldReportPostedTasksWhenDisabled(bool should_report)345 void TaskQueue::SetShouldReportPostedTasksWhenDisabled(bool should_report) {
346 impl_->SetShouldReportPostedTasksWhenDisabled(should_report);
347 }
348
IsOnMainThread() const349 bool TaskQueue::IsOnMainThread() const {
350 return associated_thread_->IsBoundToCurrentThread();
351 }
352
TakeTaskQueueImpl()353 std::unique_ptr<internal::TaskQueueImpl> TaskQueue::TakeTaskQueueImpl() {
354 base::internal::CheckedAutoLock lock(impl_lock_);
355 DCHECK(impl_);
356 return std::move(impl_);
357 }
358
359 } // namespace sequence_manager
360 } // namespace base
361