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 "base/bind.h"
8 #include "base/task/sequence_manager/sequence_manager_impl.h"
9 #include "base/task/sequence_manager/task_queue_impl.h"
10 #include "base/time/time.h"
11
12 namespace base {
13 namespace sequence_manager {
14
TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,const TaskQueue::Spec & spec)15 TaskQueue::TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,
16 const TaskQueue::Spec& spec)
17 : impl_(std::move(impl)),
18 thread_id_(PlatformThread::CurrentId()),
19 sequence_manager_(impl_ ? impl_->GetSequenceManagerWeakPtr() : nullptr),
20 graceful_queue_shutdown_helper_(
21 impl_ ? impl_->GetGracefulQueueShutdownHelper() : nullptr) {}
22
~TaskQueue()23 TaskQueue::~TaskQueue() {
24 // scoped_refptr guarantees us that this object isn't used.
25 if (!impl_)
26 return;
27 if (impl_->IsUnregistered())
28 return;
29 graceful_queue_shutdown_helper_->GracefullyShutdownTaskQueue(
30 TakeTaskQueueImpl());
31 }
32
Task(TaskQueue::PostedTask task,TimeTicks desired_run_time)33 TaskQueue::Task::Task(TaskQueue::PostedTask task, TimeTicks desired_run_time)
34 : PendingTask(task.posted_from,
35 std::move(task.callback),
36 desired_run_time,
37 task.nestable),
38 task_type_(task.task_type) {}
39
TaskTiming(bool has_wall_time,bool has_thread_time)40 TaskQueue::TaskTiming::TaskTiming(bool has_wall_time, bool has_thread_time)
41 : has_wall_time_(has_wall_time), has_thread_time_(has_thread_time) {}
42
RecordTaskStart(LazyNow * now)43 void TaskQueue::TaskTiming::RecordTaskStart(LazyNow* now) {
44 if (has_wall_time())
45 start_time_ = now->Now();
46 if (has_thread_time())
47 start_thread_time_ = base::ThreadTicks::Now();
48 }
49
RecordTaskEnd(LazyNow * now)50 void TaskQueue::TaskTiming::RecordTaskEnd(LazyNow* now) {
51 if (has_wall_time())
52 end_time_ = now->Now();
53 if (has_thread_time())
54 end_thread_time_ = base::ThreadTicks::Now();
55 }
56
PostedTask(OnceClosure callback,Location posted_from,TimeDelta delay,Nestable nestable,int task_type)57 TaskQueue::PostedTask::PostedTask(OnceClosure callback,
58 Location posted_from,
59 TimeDelta delay,
60 Nestable nestable,
61 int task_type)
62 : callback(std::move(callback)),
63 posted_from(posted_from),
64 delay(delay),
65 nestable(nestable),
66 task_type(task_type) {}
67
PostedTask(PostedTask && move_from)68 TaskQueue::PostedTask::PostedTask(PostedTask&& move_from)
69 : callback(std::move(move_from.callback)),
70 posted_from(move_from.posted_from),
71 delay(move_from.delay),
72 nestable(move_from.nestable),
73 task_type(move_from.task_type) {}
74
75 TaskQueue::PostedTask::~PostedTask() = default;
76
ShutdownTaskQueue()77 void TaskQueue::ShutdownTaskQueue() {
78 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
79 AutoLock lock(impl_lock_);
80 if (!impl_)
81 return;
82 if (!sequence_manager_) {
83 impl_.reset();
84 return;
85 }
86 impl_->SetBlameContext(nullptr);
87 impl_->SetOnTaskStartedHandler(
88 internal::TaskQueueImpl::OnTaskStartedHandler());
89 impl_->SetOnTaskCompletedHandler(
90 internal::TaskQueueImpl::OnTaskCompletedHandler());
91 sequence_manager_->UnregisterTaskQueueImpl(TakeTaskQueueImpl());
92 }
93
RunsTasksInCurrentSequence() const94 bool TaskQueue::RunsTasksInCurrentSequence() const {
95 return IsOnMainThread();
96 }
97
PostDelayedTask(const Location & from_here,OnceClosure task,TimeDelta delay)98 bool TaskQueue::PostDelayedTask(const Location& from_here,
99 OnceClosure task,
100 TimeDelta delay) {
101 return PostTaskWithMetadata(
102 PostedTask(std::move(task), from_here, delay, Nestable::kNestable));
103 }
104
PostNonNestableDelayedTask(const Location & from_here,OnceClosure task,TimeDelta delay)105 bool TaskQueue::PostNonNestableDelayedTask(const Location& from_here,
106 OnceClosure task,
107 TimeDelta delay) {
108 return PostTaskWithMetadata(
109 PostedTask(std::move(task), from_here, delay, Nestable::kNonNestable));
110 }
111
PostTaskWithMetadata(PostedTask task)112 bool TaskQueue::PostTaskWithMetadata(PostedTask task) {
113 Optional<MoveableAutoLock> lock = AcquireImplReadLockIfNeeded();
114 if (!impl_)
115 return false;
116 internal::TaskQueueImpl::PostTaskResult result(
117 impl_->PostDelayedTask(std::move(task)));
118 if (result.success)
119 return true;
120 // If posting task was unsuccessful then |result| will contain
121 // the original task which should be destructed outside of the lock.
122 lock = nullopt;
123 // Task gets implicitly destructed here.
124 return false;
125 }
126
127 std::unique_ptr<TaskQueue::QueueEnabledVoter>
CreateQueueEnabledVoter()128 TaskQueue::CreateQueueEnabledVoter() {
129 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
130 if (!impl_)
131 return nullptr;
132 return impl_->CreateQueueEnabledVoter(this);
133 }
134
IsQueueEnabled() const135 bool TaskQueue::IsQueueEnabled() const {
136 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
137 if (!impl_)
138 return false;
139 return impl_->IsQueueEnabled();
140 }
141
IsEmpty() const142 bool TaskQueue::IsEmpty() const {
143 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
144 if (!impl_)
145 return true;
146 return impl_->IsEmpty();
147 }
148
GetNumberOfPendingTasks() const149 size_t TaskQueue::GetNumberOfPendingTasks() const {
150 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
151 if (!impl_)
152 return 0;
153 return impl_->GetNumberOfPendingTasks();
154 }
155
HasTaskToRunImmediately() const156 bool TaskQueue::HasTaskToRunImmediately() const {
157 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
158 if (!impl_)
159 return false;
160 return impl_->HasTaskToRunImmediately();
161 }
162
GetNextScheduledWakeUp()163 Optional<TimeTicks> TaskQueue::GetNextScheduledWakeUp() {
164 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
165 if (!impl_)
166 return nullopt;
167 return impl_->GetNextScheduledWakeUp();
168 }
169
SetQueuePriority(TaskQueue::QueuePriority priority)170 void TaskQueue::SetQueuePriority(TaskQueue::QueuePriority priority) {
171 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
172 if (!impl_)
173 return;
174 impl_->SetQueuePriority(priority);
175 }
176
GetQueuePriority() const177 TaskQueue::QueuePriority TaskQueue::GetQueuePriority() const {
178 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
179 if (!impl_)
180 return TaskQueue::QueuePriority::kLowPriority;
181 return impl_->GetQueuePriority();
182 }
183
AddTaskObserver(MessageLoop::TaskObserver * task_observer)184 void TaskQueue::AddTaskObserver(MessageLoop::TaskObserver* task_observer) {
185 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
186 if (!impl_)
187 return;
188 impl_->AddTaskObserver(task_observer);
189 }
190
RemoveTaskObserver(MessageLoop::TaskObserver * task_observer)191 void TaskQueue::RemoveTaskObserver(MessageLoop::TaskObserver* task_observer) {
192 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
193 if (!impl_)
194 return;
195 impl_->RemoveTaskObserver(task_observer);
196 }
197
SetTimeDomain(TimeDomain * time_domain)198 void TaskQueue::SetTimeDomain(TimeDomain* time_domain) {
199 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
200 if (!impl_)
201 return;
202 impl_->SetTimeDomain(time_domain);
203 }
204
GetTimeDomain() const205 TimeDomain* TaskQueue::GetTimeDomain() const {
206 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
207 if (!impl_)
208 return nullptr;
209 return impl_->GetTimeDomain();
210 }
211
SetBlameContext(trace_event::BlameContext * blame_context)212 void TaskQueue::SetBlameContext(trace_event::BlameContext* blame_context) {
213 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
214 if (!impl_)
215 return;
216 impl_->SetBlameContext(blame_context);
217 }
218
InsertFence(InsertFencePosition position)219 void TaskQueue::InsertFence(InsertFencePosition position) {
220 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
221 if (!impl_)
222 return;
223 impl_->InsertFence(position);
224 }
225
InsertFenceAt(TimeTicks time)226 void TaskQueue::InsertFenceAt(TimeTicks time) {
227 impl_->InsertFenceAt(time);
228 }
229
RemoveFence()230 void TaskQueue::RemoveFence() {
231 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
232 if (!impl_)
233 return;
234 impl_->RemoveFence();
235 }
236
HasActiveFence()237 bool TaskQueue::HasActiveFence() {
238 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
239 if (!impl_)
240 return false;
241 return impl_->HasActiveFence();
242 }
243
BlockedByFence() const244 bool TaskQueue::BlockedByFence() const {
245 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
246 if (!impl_)
247 return false;
248 return impl_->BlockedByFence();
249 }
250
GetName() const251 const char* TaskQueue::GetName() const {
252 auto lock = AcquireImplReadLockIfNeeded();
253 if (!impl_)
254 return "";
255 return impl_->GetName();
256 }
257
SetObserver(Observer * observer)258 void TaskQueue::SetObserver(Observer* observer) {
259 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
260 if (!impl_)
261 return;
262 if (observer) {
263 // Observer is guaranteed to outlive TaskQueue and TaskQueueImpl lifecycle
264 // is controlled by |this|.
265 impl_->SetOnNextWakeUpChangedCallback(
266 BindRepeating(&TaskQueue::Observer::OnQueueNextWakeUpChanged,
267 Unretained(observer), Unretained(this)));
268 } else {
269 impl_->SetOnNextWakeUpChangedCallback(RepeatingCallback<void(TimeTicks)>());
270 }
271 }
272
IsOnMainThread() const273 bool TaskQueue::IsOnMainThread() const {
274 return thread_id_ == PlatformThread::CurrentId();
275 }
276
AcquireImplReadLockIfNeeded() const277 Optional<MoveableAutoLock> TaskQueue::AcquireImplReadLockIfNeeded() const {
278 if (IsOnMainThread())
279 return nullopt;
280 return MoveableAutoLock(impl_lock_);
281 }
282
TakeTaskQueueImpl()283 std::unique_ptr<internal::TaskQueueImpl> TaskQueue::TakeTaskQueueImpl() {
284 DCHECK(impl_);
285 return std::move(impl_);
286 }
287
288 } // namespace sequence_manager
289 } // namespace base
290