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 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 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 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 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 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 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 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 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 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 94 bool TaskQueue::RunsTasksInCurrentSequence() const { 95 return IsOnMainThread(); 96 } 97 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 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 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> 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 135 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 142 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 149 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 156 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 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 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 177 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 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 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 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 205 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 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 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 226 void TaskQueue::InsertFenceAt(TimeTicks time) { 227 impl_->InsertFenceAt(time); 228 } 229 230 void TaskQueue::RemoveFence() { 231 DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_); 232 if (!impl_) 233 return; 234 impl_->RemoveFence(); 235 } 236 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 244 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 251 const char* TaskQueue::GetName() const { 252 auto lock = AcquireImplReadLockIfNeeded(); 253 if (!impl_) 254 return ""; 255 return impl_->GetName(); 256 } 257 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 273 bool TaskQueue::IsOnMainThread() const { 274 return thread_id_ == PlatformThread::CurrentId(); 275 } 276 277 Optional<MoveableAutoLock> TaskQueue::AcquireImplReadLockIfNeeded() const { 278 if (IsOnMainThread()) 279 return nullopt; 280 return MoveableAutoLock(impl_lock_); 281 } 282 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