Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/scheduler/base/task_queue_impl.h" | 5 #include "platform/scheduler/base/task_queue_impl.h" |
| 6 | 6 |
| 7 #include "base/trace_event/blame_context.h" | 7 #include "base/trace_event/blame_context.h" |
| 8 #include "platform/scheduler/base/task_queue_manager.h" | 8 #include "platform/scheduler/base/task_queue_manager.h" |
| 9 #include "platform/scheduler/base/task_queue_manager_delegate.h" | 9 #include "platform/scheduler/base/task_queue_manager_delegate.h" |
| 10 #include "platform/scheduler/base/time_domain.h" | 10 #include "platform/scheduler/base/time_domain.h" |
| 11 #include "platform/scheduler/base/work_queue.h" | 11 #include "platform/scheduler/base/work_queue.h" |
| 12 | 12 |
| 13 namespace blink { | 13 namespace blink { |
| 14 namespace scheduler { | 14 namespace scheduler { |
| 15 | 15 |
| 16 TaskQueue::TaskHandle::TaskHandle() : enqueue_order_(0), sequence_number_(0) {} | |
| 17 | |
| 18 TaskQueue::TaskHandle::TaskHandle(TaskQueue* task_queue, uint64_t enqueue_order) | |
| 19 : enqueue_order_(enqueue_order), | |
| 20 #if DCHECK_IS_ON() | |
| 21 task_queue_(task_queue), | |
| 22 #endif | |
| 23 sequence_number_(0) { | |
| 24 DCHECK_GT(enqueue_order, 0ull); | |
| 25 } | |
| 26 | |
| 27 TaskQueue::TaskHandle::TaskHandle(TaskQueue* task_queue, | |
| 28 base::TimeTicks scheduled_run_time, | |
| 29 int sequence_number) | |
| 30 : enqueue_order_(0), | |
| 31 scheduled_run_time_(scheduled_run_time), | |
| 32 #if DCHECK_IS_ON() | |
| 33 task_queue_(task_queue), | |
| 34 #endif | |
| 35 sequence_number_(sequence_number) { | |
| 36 DCHECK(!scheduled_run_time.is_null()); | |
| 37 } | |
| 38 | |
| 39 TaskQueue::TaskHandle::operator bool() const { | |
| 40 return !scheduled_run_time_.is_null() || | |
| 41 internal::EnqueueOrderGenerator::IsValidEnqueueOrder(enqueue_order_); | |
| 42 } | |
| 43 | |
| 44 namespace internal { | 16 namespace internal { |
| 45 | 17 |
| 46 TaskQueueImpl::TaskQueueImpl( | 18 TaskQueueImpl::TaskQueueImpl( |
| 47 TaskQueueManager* task_queue_manager, | 19 TaskQueueManager* task_queue_manager, |
| 48 TimeDomain* time_domain, | 20 TimeDomain* time_domain, |
| 49 const Spec& spec, | 21 const Spec& spec, |
| 50 const char* disabled_by_default_tracing_category, | 22 const char* disabled_by_default_tracing_category, |
| 51 const char* disabled_by_default_verbose_tracing_category) | 23 const char* disabled_by_default_verbose_tracing_category) |
| 52 : thread_id_(base::PlatformThread::CurrentId()), | 24 : thread_id_(base::PlatformThread::CurrentId()), |
| 53 any_thread_(task_queue_manager, time_domain), | 25 any_thread_(task_queue_manager, time_domain), |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 bool nestable, | 81 bool nestable, |
| 110 EnqueueOrder enqueue_order) | 82 EnqueueOrder enqueue_order) |
| 111 : PendingTask(posted_from, task, desired_run_time, nestable), | 83 : PendingTask(posted_from, task, desired_run_time, nestable), |
| 112 #ifndef NDEBUG | 84 #ifndef NDEBUG |
| 113 enqueue_order_set_(true), | 85 enqueue_order_set_(true), |
| 114 #endif | 86 #endif |
| 115 enqueue_order_(enqueue_order) { | 87 enqueue_order_(enqueue_order) { |
| 116 sequence_num = sequence_number; | 88 sequence_num = sequence_number; |
| 117 } | 89 } |
| 118 | 90 |
| 119 // static | |
| 120 TaskQueueImpl::Task TaskQueueImpl::Task::CreateFakeTaskFromHandle( | |
| 121 const TaskHandle& handle) { | |
| 122 if (handle.scheduled_run_time_.is_null()) { | |
| 123 // It's an immediate task. | |
| 124 return Task(tracked_objects::Location(), base::Closure(), | |
| 125 handle.scheduled_run_time_, handle.sequence_number_, false, | |
| 126 handle.enqueue_order_); | |
| 127 } else { | |
| 128 // It's a delayed task. | |
| 129 DCHECK_EQ(0ull, handle.enqueue_order_); | |
| 130 return Task(tracked_objects::Location(), base::Closure(), | |
| 131 handle.scheduled_run_time_, handle.sequence_number_, false); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 bool TaskQueueImpl::Task::DelayedRunTimeComparator::operator()( | |
| 136 const Task& a, | |
| 137 const Task& b) const { | |
| 138 if (a.delayed_run_time < b.delayed_run_time) | |
| 139 return true; | |
| 140 | |
| 141 if (a.delayed_run_time > b.delayed_run_time) | |
| 142 return false; | |
| 143 | |
| 144 // If the times happen to match, then we use the sequence number to decide. | |
| 145 // Compare the difference to support integer roll-over. | |
| 146 return (a.sequence_num - b.sequence_num) < 0; | |
| 147 } | |
| 148 | |
| 149 // static | |
| 150 bool TaskQueueImpl::Task::EnqueueOrderComparatorFn(const Task& a, | |
| 151 const Task& b) { | |
| 152 return a.enqueue_order() < b.enqueue_order(); | |
| 153 } | |
| 154 | |
| 155 // static | |
| 156 bool TaskQueueImpl::Task::DelayedRunTimeComparatorFn(const Task& a, | |
| 157 const Task& b) { | |
| 158 if (a.delayed_run_time < b.delayed_run_time) | |
| 159 return true; | |
| 160 | |
| 161 if (a.delayed_run_time > b.delayed_run_time) | |
| 162 return false; | |
| 163 | |
| 164 // If the times happen to match, then we use the sequence number to decide. | |
| 165 // Compare the difference to support integer roll-over. | |
| 166 return (a.sequence_num - b.sequence_num) < 0; | |
| 167 } | |
| 168 | |
| 169 TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager, | 91 TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager, |
| 170 TimeDomain* time_domain) | 92 TimeDomain* time_domain) |
| 171 : task_queue_manager(task_queue_manager), | 93 : task_queue_manager(task_queue_manager), time_domain(time_domain) {} |
| 172 time_domain(time_domain), | |
| 173 immediate_incoming_queue(&TaskQueueImpl::Task::EnqueueOrderComparatorFn) { | |
| 174 } | |
| 175 | 94 |
| 176 TaskQueueImpl::AnyThread::~AnyThread() {} | 95 TaskQueueImpl::AnyThread::~AnyThread() {} |
| 177 | 96 |
| 178 TaskQueueImpl::MainThreadOnly::MainThreadOnly( | 97 TaskQueueImpl::MainThreadOnly::MainThreadOnly( |
| 179 TaskQueueManager* task_queue_manager, | 98 TaskQueueManager* task_queue_manager, |
| 180 TaskQueueImpl* task_queue, | 99 TaskQueueImpl* task_queue, |
| 181 TimeDomain* time_domain) | 100 TimeDomain* time_domain) |
| 182 : task_queue_manager(task_queue_manager), | 101 : task_queue_manager(task_queue_manager), |
| 183 time_domain(time_domain), | 102 time_domain(time_domain), |
| 184 delayed_work_queue( | 103 delayed_work_queue(new WorkQueue(task_queue, "delayed")), |
| 185 new WorkQueue(task_queue, | 104 immediate_work_queue(new WorkQueue(task_queue, "immediate")), |
| 186 "delayed", | |
| 187 &TaskQueueImpl::Task::DelayedRunTimeComparatorFn)), | |
| 188 immediate_work_queue( | |
| 189 new WorkQueue(task_queue, | |
| 190 "immediate", | |
| 191 &TaskQueueImpl::Task::EnqueueOrderComparatorFn)), | |
| 192 set_index(0), | 105 set_index(0), |
| 193 is_enabled(true), | 106 is_enabled(true), |
| 194 blame_context(nullptr), | 107 blame_context(nullptr), |
| 195 current_fence(0) {} | 108 current_fence(0) {} |
| 196 | 109 |
| 197 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} | 110 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} |
| 198 | 111 |
| 199 void TaskQueueImpl::UnregisterTaskQueue() { | 112 void TaskQueueImpl::UnregisterTaskQueue() { |
| 200 base::AutoLock lock(any_thread_lock_); | 113 base::AutoLock lock(any_thread_lock_); |
| 201 if (main_thread_only().time_domain) | 114 if (main_thread_only().time_domain) |
| 202 main_thread_only().time_domain->UnregisterQueue(this); | 115 main_thread_only().time_domain->UnregisterQueue(this); |
| 203 if (!any_thread().task_queue_manager) | 116 if (!any_thread().task_queue_manager) |
| 204 return; | 117 return; |
| 205 any_thread().time_domain = nullptr; | 118 any_thread().time_domain = nullptr; |
| 206 main_thread_only().time_domain = nullptr; | 119 main_thread_only().time_domain = nullptr; |
| 207 any_thread().task_queue_manager->UnregisterTaskQueue(this); | 120 any_thread().task_queue_manager->UnregisterTaskQueue(this); |
| 208 | 121 |
| 209 any_thread().task_queue_manager = nullptr; | 122 any_thread().task_queue_manager = nullptr; |
| 210 main_thread_only().task_queue_manager = nullptr; | 123 main_thread_only().task_queue_manager = nullptr; |
| 211 main_thread_only().delayed_incoming_queue.clear(); | 124 main_thread_only().delayed_incoming_queue = std::priority_queue<Task>(); |
| 212 any_thread().immediate_incoming_queue.clear(); | 125 any_thread().immediate_incoming_queue = std::queue<Task>(); |
| 213 main_thread_only().immediate_work_queue.reset(); | 126 main_thread_only().immediate_work_queue.reset(); |
| 214 main_thread_only().delayed_work_queue.reset(); | 127 main_thread_only().delayed_work_queue.reset(); |
| 215 } | 128 } |
| 216 | 129 |
| 217 bool TaskQueueImpl::RunsTasksOnCurrentThread() const { | 130 bool TaskQueueImpl::RunsTasksOnCurrentThread() const { |
| 218 base::AutoLock lock(any_thread_lock_); | 131 base::AutoLock lock(any_thread_lock_); |
| 219 return base::PlatformThread::CurrentId() == thread_id_; | 132 return base::PlatformThread::CurrentId() == thread_id_; |
| 220 } | 133 } |
| 221 | 134 |
| 222 TaskQueue::TaskHandle TaskQueueImpl::PostCancellableDelayedTask( | |
| 223 const tracked_objects::Location& from_here, | |
| 224 const base::Closure& task, | |
| 225 base::TimeDelta delay) { | |
| 226 if (!main_thread_only().task_queue_manager) | |
| 227 return TaskHandle(); | |
| 228 | |
| 229 EnqueueOrder sequence_number = | |
| 230 main_thread_only().task_queue_manager->GetNextSequenceNumber(); | |
| 231 | |
| 232 if (delay.is_zero()) { | |
| 233 base::AutoLock lock(any_thread_lock_); | |
| 234 PushOntoImmediateIncomingQueueLocked( | |
| 235 Task(from_here, task, base::TimeTicks(), sequence_number, true, | |
| 236 sequence_number)); | |
| 237 | |
| 238 return TaskHandle(this, sequence_number); | |
| 239 } else { | |
| 240 DCHECK_GT(delay, base::TimeDelta()); | |
| 241 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); | |
| 242 base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; | |
| 243 PushOntoDelayedIncomingQueueFromMainThread( | |
| 244 Task(from_here, task, time_domain_delayed_run_time, sequence_number, | |
| 245 true), | |
| 246 time_domain_now); | |
| 247 | |
| 248 return TaskHandle(this, time_domain_delayed_run_time, sequence_number); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 bool TaskQueueImpl::CancelTask(const TaskQueue::TaskHandle& handle) { | |
| 253 if (!handle) | |
| 254 return false; | |
| 255 | |
| 256 // If the TaskQueueManager has gone away, pretend we have canceled the task | |
| 257 // because this simplifies logic in TimerBase::stop. | |
| 258 if (!main_thread_only().task_queue_manager) | |
| 259 return true; | |
| 260 | |
| 261 #if DCHECK_IS_ON() | |
| 262 DCHECK_EQ(handle.task_queue_, this); | |
| 263 #endif | |
| 264 | |
| 265 Task fake_task = Task::CreateFakeTaskFromHandle(handle); | |
| 266 if (handle.scheduled_run_time_.is_null()) { | |
| 267 // It's an immediate task. | |
| 268 if (main_thread_only().immediate_work_queue->CancelTask(fake_task)) | |
| 269 return true; | |
| 270 | |
| 271 base::AutoLock lock(any_thread_lock_); | |
| 272 return any_thread().immediate_incoming_queue.erase(fake_task) > 0; | |
| 273 } else { | |
| 274 // It's a delayed task. | |
| 275 DelayedRunTimeQueue::iterator it = | |
| 276 main_thread_only().delayed_incoming_queue.find(fake_task); | |
| 277 if (it != main_thread_only().delayed_incoming_queue.end()) { | |
| 278 // It's safe to remove the wakeup from the TimeDomain only if this task's | |
| 279 // scheduled run time was unique within the queue. | |
| 280 bool can_cancel_timedomain_wakeup = true; | |
| 281 if (it != main_thread_only().delayed_incoming_queue.begin()) { | |
| 282 DelayedRunTimeQueue::iterator before = it; | |
| 283 before--; | |
| 284 if (before->delayed_run_time == handle.scheduled_run_time_) | |
| 285 can_cancel_timedomain_wakeup = false; | |
| 286 } | |
| 287 if (can_cancel_timedomain_wakeup) { | |
| 288 DelayedRunTimeQueue::iterator after = it; | |
| 289 after++; | |
| 290 if (after != main_thread_only().delayed_incoming_queue.end() && | |
| 291 after->delayed_run_time == handle.scheduled_run_time_) { | |
| 292 can_cancel_timedomain_wakeup = false; | |
| 293 } | |
| 294 } | |
| 295 if (can_cancel_timedomain_wakeup) { | |
| 296 main_thread_only().time_domain->CancelDelayedWork( | |
| 297 this, handle.scheduled_run_time_); | |
| 298 } | |
| 299 | |
| 300 main_thread_only().delayed_incoming_queue.erase(it); | |
| 301 return true; | |
| 302 } | |
| 303 | |
| 304 return main_thread_only().delayed_work_queue->CancelTask(fake_task); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 bool TaskQueueImpl::IsTaskPending(const TaskQueue::TaskHandle& handle) const { | |
| 309 if (!handle) | |
| 310 return false; | |
| 311 | |
| 312 // If the TaskQueueManager has gone away the task got cancelled. | |
| 313 if (!main_thread_only().task_queue_manager) | |
| 314 return false; | |
| 315 | |
| 316 #if DCHECK_IS_ON() | |
| 317 DCHECK_EQ(handle.task_queue_, this); | |
| 318 #endif | |
| 319 | |
| 320 Task fake_task = Task::CreateFakeTaskFromHandle(handle); | |
| 321 if (handle.scheduled_run_time_.is_null()) { | |
| 322 // It's an immediate task. | |
| 323 if (main_thread_only().immediate_work_queue->IsTaskPending(fake_task)) | |
| 324 return true; | |
| 325 | |
| 326 base::AutoLock lock(any_thread_lock_); | |
| 327 return any_thread().immediate_incoming_queue.find(fake_task) != | |
| 328 any_thread().immediate_incoming_queue.end(); | |
| 329 } else { | |
| 330 // It's a delayed task. | |
| 331 DelayedRunTimeQueue::iterator it = | |
| 332 main_thread_only().delayed_incoming_queue.find(fake_task); | |
| 333 if (it != main_thread_only().delayed_incoming_queue.end()) | |
| 334 return true; | |
| 335 | |
| 336 return main_thread_only().delayed_work_queue->IsTaskPending(fake_task); | |
| 337 } | |
| 338 } | |
| 339 | 135 |
| 340 bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, | 136 bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, |
| 341 const base::Closure& task, | 137 const base::Closure& task, |
| 342 base::TimeDelta delay) { | 138 base::TimeDelta delay) { |
| 343 if (delay.is_zero()) | 139 if (delay.is_zero()) |
| 344 return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); | 140 return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); |
| 345 | 141 |
| 346 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); | 142 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); |
| 347 } | 143 } |
| 348 | 144 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 task_type != TaskType::NON_NESTABLE)); | 208 task_type != TaskType::NON_NESTABLE)); |
| 413 } | 209 } |
| 414 return true; | 210 return true; |
| 415 } | 211 } |
| 416 | 212 |
| 417 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( | 213 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( |
| 418 Task pending_task, | 214 Task pending_task, |
| 419 base::TimeTicks now) { | 215 base::TimeTicks now) { |
| 420 main_thread_only().task_queue_manager->DidQueueTask(pending_task); | 216 main_thread_only().task_queue_manager->DidQueueTask(pending_task); |
| 421 | 217 |
| 422 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue. | 218 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue.. |
|
Sami
2016/09/08 16:35:02
nit: extra '.'?
alex clarke (OOO till 29th)
2016/09/08 16:43:28
Done.
| |
| 423 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; | 219 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; |
| 424 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 220 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
| 425 main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, | 221 main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, |
| 426 now); | 222 now); |
| 427 TraceQueueSize(false); | 223 TraceQueueSize(false); |
| 428 } | 224 } |
| 429 | 225 |
| 430 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { | 226 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { |
| 431 any_thread().task_queue_manager->DidQueueTask(pending_task); | 227 any_thread().task_queue_manager->DidQueueTask(pending_task); |
| 432 | 228 |
| 433 int thread_hop_task_sequence_number = | 229 int thread_hop_task_sequence_number = |
| 434 any_thread().task_queue_manager->GetNextSequenceNumber(); | 230 any_thread().task_queue_manager->GetNextSequenceNumber(); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 448 // There's no point posting a DoWork for a disabled queue, however we can | 244 // There's no point posting a DoWork for a disabled queue, however we can |
| 449 // only tell if it's disabled from the main thread. | 245 // only tell if it's disabled from the main thread. |
| 450 if (base::PlatformThread::CurrentId() == thread_id_) { | 246 if (base::PlatformThread::CurrentId() == thread_id_) { |
| 451 if (main_thread_only().is_enabled && !BlockedByFenceLocked()) | 247 if (main_thread_only().is_enabled && !BlockedByFenceLocked()) |
| 452 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 248 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
| 453 } else { | 249 } else { |
| 454 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 250 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
| 455 } | 251 } |
| 456 } | 252 } |
| 457 any_thread().task_queue_manager->DidQueueTask(pending_task); | 253 any_thread().task_queue_manager->DidQueueTask(pending_task); |
| 458 // We expect |pending_task| to be inserted at the end. Amoritized O(1). | 254 any_thread().immediate_incoming_queue.push(std::move(pending_task)); |
| 459 any_thread().immediate_incoming_queue.insert( | |
| 460 any_thread().immediate_incoming_queue.end(), | |
| 461 std::move(pending_task)); | |
| 462 DCHECK_EQ(pending_task.enqueue_order(), | |
| 463 any_thread().immediate_incoming_queue.rbegin()->enqueue_order()); | |
| 464 TraceQueueSize(true); | 255 TraceQueueSize(true); |
| 465 } | 256 } |
| 466 | 257 |
| 467 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { | 258 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { |
| 468 DCHECK(main_thread_checker_.CalledOnValidThread()); | 259 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 469 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; | 260 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; |
| 470 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); | 261 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); |
| 471 // Make sure |delayed_run_time| isn't in the past. | 262 // Make sure |delayed_run_time| isn't in the past. |
| 472 if (delayed_run_time < time_domain_now) { | 263 if (delayed_run_time < time_domain_now) { |
| 473 delayed_run_time = time_domain_now; | 264 delayed_run_time = time_domain_now; |
| 474 pending_task.delayed_run_time = time_domain_now; | 265 pending_task.delayed_run_time = time_domain_now; |
| 475 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 266 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
| 476 LazyNow lazy_now(time_domain_now); | 267 LazyNow lazy_now(time_domain_now); |
| 477 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now); | 268 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now); |
| 478 } else { | 269 } else { |
| 479 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 270 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
| 480 main_thread_only().time_domain->ScheduleDelayedWork( | 271 main_thread_only().time_domain->ScheduleDelayedWork( |
| 481 this, delayed_run_time, main_thread_only().time_domain->Now()); | 272 this, delayed_run_time, main_thread_only().time_domain->Now()); |
| 482 } | 273 } |
| 483 TraceQueueSize(false); | 274 TraceQueueSize(false); |
| 484 } | 275 } |
| 485 | 276 |
| 486 void TaskQueueImpl::SetQueueEnabled(bool enabled) { | 277 void TaskQueueImpl::SetQueueEnabled(bool enabled) { |
| 487 if (main_thread_only().is_enabled == enabled) | 278 if (main_thread_only().is_enabled == enabled) |
| 488 return; | 279 return; |
| 489 main_thread_only().is_enabled = enabled; | 280 main_thread_only().is_enabled = enabled; |
| 490 if (!main_thread_only().task_queue_manager) | 281 if (!main_thread_only().task_queue_manager) |
| 491 return; | 282 return; |
| 492 if (enabled) { | 283 if (enabled) { |
| 493 // Note it's the job of the selector to tell the TaskQueueManager if | 284 // Note it's the job of the selector to tell the TaskQueueManager if |
| 494 // a DoWork needs posting. | 285 // a DoWork needs posting. |
| 495 main_thread_only().task_queue_manager->selector_.EnableQueue(this); | 286 main_thread_only().task_queue_manager->selector_.EnableQueue(this); |
| 496 } else { | 287 } else { |
| 497 main_thread_only().task_queue_manager->selector_.DisableQueue(this); | 288 main_thread_only().task_queue_manager->selector_.DisableQueue(this); |
| 498 } | 289 } |
| 499 } | 290 } |
| 500 | 291 |
| 501 bool TaskQueueImpl::IsQueueEnabled() const { | 292 bool TaskQueueImpl::IsQueueEnabled() const { |
| 502 return main_thread_only().is_enabled; | 293 return main_thread_only().is_enabled; |
| 503 } | 294 } |
| 504 | 295 |
| 505 bool TaskQueueImpl::IsEmpty() const { | 296 bool TaskQueueImpl::IsEmpty() const { |
| 506 if (!main_thread_only().delayed_work_queue->Empty() || | 297 if (!main_thread_only().delayed_work_queue->Empty() || |
| 298 !main_thread_only().delayed_incoming_queue.empty() || | |
| 507 !main_thread_only().immediate_work_queue->Empty()) { | 299 !main_thread_only().immediate_work_queue->Empty()) { |
| 508 return false; | 300 return false; |
| 509 } | 301 } |
| 510 | 302 |
| 511 base::AutoLock lock(any_thread_lock_); | 303 base::AutoLock lock(any_thread_lock_); |
| 512 return any_thread().immediate_incoming_queue.empty() && | 304 return any_thread().immediate_incoming_queue.empty(); |
| 513 main_thread_only().delayed_incoming_queue.empty(); | |
| 514 } | 305 } |
| 515 | 306 |
| 516 bool TaskQueueImpl::HasPendingImmediateWork() const { | 307 bool TaskQueueImpl::HasPendingImmediateWork() const { |
| 517 // Any work queue tasks count as immediate work. | 308 // Any work queue tasks count as immediate work. |
| 518 if (!main_thread_only().delayed_work_queue->Empty() || | 309 if (!main_thread_only().delayed_work_queue->Empty() || |
| 519 !main_thread_only().immediate_work_queue->Empty()) { | 310 !main_thread_only().immediate_work_queue->Empty()) { |
| 520 return true; | 311 return true; |
| 521 } | 312 } |
| 522 | 313 |
| 523 // Tasks on |delayed_incoming_queue| that could run now, count as | 314 // Tasks on |delayed_incoming_queue| that could run now, count as |
| 524 // immediate work. | 315 // immediate work. |
| 525 if (!main_thread_only().delayed_incoming_queue.empty() && | 316 if (!main_thread_only().delayed_incoming_queue.empty() && |
| 526 main_thread_only().delayed_incoming_queue.begin()->delayed_run_time <= | 317 main_thread_only().delayed_incoming_queue.top().delayed_run_time <= |
| 527 main_thread_only().time_domain->CreateLazyNow().Now()) { | 318 main_thread_only().time_domain->CreateLazyNow().Now()) { |
| 528 return true; | 319 return true; |
| 529 } | 320 } |
| 530 | 321 |
| 531 // Finally tasks on |immediate_incoming_queue| count as immediate work. | 322 // Finally tasks on |immediate_incoming_queue| count as immediate work. |
| 532 base::AutoLock lock(any_thread_lock_); | 323 base::AutoLock lock(any_thread_lock_); |
| 533 return !any_thread().immediate_incoming_queue.empty(); | 324 return !any_thread().immediate_incoming_queue.empty(); |
| 534 } | 325 } |
| 535 | 326 |
| 536 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { | 327 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { |
| 537 // Enqueue all delayed tasks that should be running now. | 328 // Enqueue all delayed tasks that should be running now. |
| 538 while (!main_thread_only().delayed_incoming_queue.empty()) { | 329 while (!main_thread_only().delayed_incoming_queue.empty()) { |
| 539 DelayedRunTimeQueue::iterator next_task = | 330 // TODO(alexclarke): Use extract() when C++17 is allowed. |
| 540 main_thread_only().delayed_incoming_queue.begin(); | 331 Task& task = |
| 541 if (next_task->delayed_run_time > lazy_now->Now()) | 332 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()); |
| 333 if (task.task.IsCancelled()) { | |
| 334 main_thread_only().delayed_incoming_queue.pop(); | |
| 335 continue; | |
| 336 } | |
| 337 if (task.delayed_run_time > lazy_now->Now()) | |
| 542 break; | 338 break; |
| 543 // TODO(alexclarke): Use extract() when C++17 is allowed. | |
| 544 Task& task = const_cast<Task&>(*next_task); | |
| 545 task.set_enqueue_order( | 339 task.set_enqueue_order( |
| 546 main_thread_only().task_queue_manager->GetNextSequenceNumber()); | 340 main_thread_only().task_queue_manager->GetNextSequenceNumber()); |
| 547 main_thread_only().delayed_work_queue->Push(std::move(task)); | 341 main_thread_only().delayed_work_queue->Push(std::move(task)); |
| 548 main_thread_only().delayed_incoming_queue.erase(next_task); | 342 main_thread_only().delayed_incoming_queue.pop(); |
| 549 } | 343 } |
| 550 } | 344 } |
| 551 | 345 |
| 552 void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now) { | 346 bool TaskQueueImpl::MaybeUpdateImmediateWorkQueues() { |
| 553 if (!main_thread_only().task_queue_manager) | 347 if (!main_thread_only().task_queue_manager) |
| 554 return; | 348 return false; |
| 555 MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); | |
| 556 TraceQueueSize(false); | |
| 557 } | |
| 558 | 349 |
| 559 void TaskQueueImpl::UpdateImmediateWorkQueue() { | 350 if (!main_thread_only().immediate_work_queue->Empty()) |
| 560 DCHECK(main_thread_only().immediate_work_queue->Empty()); | 351 return true; |
| 352 | |
| 561 base::AutoLock lock(any_thread_lock_); | 353 base::AutoLock lock(any_thread_lock_); |
| 562 if (!main_thread_only().task_queue_manager) | |
| 563 return; | |
| 564 | |
| 565 main_thread_only().immediate_work_queue->SwapLocked( | 354 main_thread_only().immediate_work_queue->SwapLocked( |
| 566 any_thread().immediate_incoming_queue); | 355 any_thread().immediate_incoming_queue); |
| 567 | 356 // |immediate_work_queue| is now empty so updates are no longer required. |
| 568 // |any_thread().immediate_incoming_queue| is now empty so | 357 return false; |
| 569 // TimeDomain::UpdateQueues no longer needs to consider this queue for | |
| 570 // reloading. | |
| 571 main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); | |
| 572 } | 358 } |
| 573 | 359 |
| 574 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { | 360 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { |
| 575 bool is_tracing; | 361 bool is_tracing; |
| 576 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, | 362 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, |
| 577 &is_tracing); | 363 &is_tracing); |
| 578 if (!is_tracing) | 364 if (!is_tracing) |
| 579 return; | 365 return; |
| 580 | 366 |
| 581 // It's only safe to access the work queues from the main thread. | 367 // It's only safe to access the work queues from the main thread. |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 643 state->SetInteger("immediate_incoming_queue_size", | 429 state->SetInteger("immediate_incoming_queue_size", |
| 644 any_thread().immediate_incoming_queue.size()); | 430 any_thread().immediate_incoming_queue.size()); |
| 645 state->SetInteger("delayed_incoming_queue_size", | 431 state->SetInteger("delayed_incoming_queue_size", |
| 646 main_thread_only().delayed_incoming_queue.size()); | 432 main_thread_only().delayed_incoming_queue.size()); |
| 647 state->SetInteger("immediate_work_queue_size", | 433 state->SetInteger("immediate_work_queue_size", |
| 648 main_thread_only().immediate_work_queue->Size()); | 434 main_thread_only().immediate_work_queue->Size()); |
| 649 state->SetInteger("delayed_work_queue_size", | 435 state->SetInteger("delayed_work_queue_size", |
| 650 main_thread_only().delayed_work_queue->Size()); | 436 main_thread_only().delayed_work_queue->Size()); |
| 651 if (!main_thread_only().delayed_incoming_queue.empty()) { | 437 if (!main_thread_only().delayed_incoming_queue.empty()) { |
| 652 base::TimeDelta delay_to_next_task = | 438 base::TimeDelta delay_to_next_task = |
| 653 (main_thread_only().delayed_incoming_queue.begin()->delayed_run_time - | 439 (main_thread_only().delayed_incoming_queue.top().delayed_run_time - |
| 654 main_thread_only().time_domain->CreateLazyNow().Now()); | 440 main_thread_only().time_domain->CreateLazyNow().Now()); |
| 655 state->SetDouble("delay_to_next_task_ms", | 441 state->SetDouble("delay_to_next_task_ms", |
| 656 delay_to_next_task.InMillisecondsF()); | 442 delay_to_next_task.InMillisecondsF()); |
| 657 } | 443 } |
| 658 if (verbose_tracing_enabled) { | 444 if (verbose_tracing_enabled) { |
| 659 state->BeginArray("immediate_incoming_queue"); | 445 state->BeginArray("immediate_incoming_queue"); |
| 660 QueueAsValueInto(any_thread().immediate_incoming_queue, state); | 446 QueueAsValueInto(any_thread().immediate_incoming_queue, state); |
| 661 state->EndArray(); | 447 state->EndArray(); |
| 662 state->BeginArray("delayed_work_queue"); | 448 state->BeginArray("delayed_work_queue"); |
| 663 main_thread_only().delayed_work_queue->AsValueInto(state); | 449 main_thread_only().delayed_work_queue->AsValueInto(state); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 746 // Tasks posted after this point will have a strictly higher enqueue order | 532 // Tasks posted after this point will have a strictly higher enqueue order |
| 747 // and will be blocked from running. | 533 // and will be blocked from running. |
| 748 bool task_unblocked = main_thread_only().immediate_work_queue->InsertFence( | 534 bool task_unblocked = main_thread_only().immediate_work_queue->InsertFence( |
| 749 main_thread_only().current_fence); | 535 main_thread_only().current_fence); |
| 750 task_unblocked |= main_thread_only().delayed_work_queue->InsertFence( | 536 task_unblocked |= main_thread_only().delayed_work_queue->InsertFence( |
| 751 main_thread_only().current_fence); | 537 main_thread_only().current_fence); |
| 752 | 538 |
| 753 if (!task_unblocked && previous_fence) { | 539 if (!task_unblocked && previous_fence) { |
| 754 base::AutoLock lock(any_thread_lock_); | 540 base::AutoLock lock(any_thread_lock_); |
| 755 if (!any_thread().immediate_incoming_queue.empty() && | 541 if (!any_thread().immediate_incoming_queue.empty() && |
| 756 any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 542 any_thread().immediate_incoming_queue.front().enqueue_order() > |
| 757 previous_fence && | 543 previous_fence && |
| 758 any_thread().immediate_incoming_queue.begin()->enqueue_order() < | 544 any_thread().immediate_incoming_queue.front().enqueue_order() < |
| 759 main_thread_only().current_fence) { | 545 main_thread_only().current_fence) { |
| 760 task_unblocked = true; | 546 task_unblocked = true; |
| 761 } | 547 } |
| 762 } | 548 } |
| 763 | 549 |
| 764 if (main_thread_only().is_enabled && task_unblocked) { | 550 if (main_thread_only().is_enabled && task_unblocked) { |
| 765 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( | 551 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
| 766 FROM_HERE); | 552 FROM_HERE); |
| 767 } | 553 } |
| 768 } | 554 } |
| 769 | 555 |
| 770 void TaskQueueImpl::RemoveFence() { | 556 void TaskQueueImpl::RemoveFence() { |
| 771 if (!main_thread_only().task_queue_manager) | 557 if (!main_thread_only().task_queue_manager) |
| 772 return; | 558 return; |
| 773 | 559 |
| 774 EnqueueOrder previous_fence = main_thread_only().current_fence; | 560 EnqueueOrder previous_fence = main_thread_only().current_fence; |
| 775 main_thread_only().current_fence = 0; | 561 main_thread_only().current_fence = 0; |
| 776 | 562 |
| 777 bool task_unblocked = main_thread_only().immediate_work_queue->RemoveFence(); | 563 bool task_unblocked = main_thread_only().immediate_work_queue->RemoveFence(); |
| 778 task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence(); | 564 task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence(); |
| 779 | 565 |
| 780 if (!task_unblocked && previous_fence) { | 566 if (!task_unblocked && previous_fence) { |
| 781 base::AutoLock lock(any_thread_lock_); | 567 base::AutoLock lock(any_thread_lock_); |
| 782 if (!any_thread().immediate_incoming_queue.empty() && | 568 if (!any_thread().immediate_incoming_queue.empty() && |
| 783 any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 569 any_thread().immediate_incoming_queue.front().enqueue_order() > |
| 784 previous_fence) { | 570 previous_fence) { |
| 785 task_unblocked = true; | 571 task_unblocked = true; |
| 786 } | 572 } |
| 787 } | 573 } |
| 788 | 574 |
| 789 if (main_thread_only().is_enabled && task_unblocked) { | 575 if (main_thread_only().is_enabled && task_unblocked) { |
| 790 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( | 576 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
| 791 FROM_HERE); | 577 FROM_HERE); |
| 792 } | 578 } |
| 793 } | 579 } |
| 794 | 580 |
| 795 bool TaskQueueImpl::BlockedByFence() const { | 581 bool TaskQueueImpl::BlockedByFence() const { |
| 796 if (!main_thread_only().current_fence) | 582 if (!main_thread_only().current_fence) |
| 797 return false; | 583 return false; |
| 798 | 584 |
| 799 if (!main_thread_only().immediate_work_queue->BlockedByFence() || | 585 if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
| 800 !main_thread_only().delayed_work_queue->BlockedByFence()) { | 586 !main_thread_only().delayed_work_queue->BlockedByFence()) { |
| 801 return false; | 587 return false; |
| 802 } | 588 } |
| 803 | 589 |
| 804 base::AutoLock lock(any_thread_lock_); | 590 base::AutoLock lock(any_thread_lock_); |
| 805 if (any_thread().immediate_incoming_queue.empty()) | 591 if (any_thread().immediate_incoming_queue.empty()) |
| 806 return true; | 592 return true; |
| 807 | 593 |
| 808 return any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 594 return any_thread().immediate_incoming_queue.front().enqueue_order() > |
| 809 main_thread_only().current_fence; | 595 main_thread_only().current_fence; |
| 810 } | 596 } |
| 811 | 597 |
| 812 bool TaskQueueImpl::BlockedByFenceLocked() const { | 598 bool TaskQueueImpl::BlockedByFenceLocked() const { |
| 813 if (!main_thread_only().current_fence) | 599 if (!main_thread_only().current_fence) |
| 814 return false; | 600 return false; |
| 815 | 601 |
| 816 if (!main_thread_only().immediate_work_queue->BlockedByFence() || | 602 if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
| 817 !main_thread_only().delayed_work_queue->BlockedByFence()) { | 603 !main_thread_only().delayed_work_queue->BlockedByFence()) { |
| 818 return false; | 604 return false; |
| 819 } | 605 } |
| 820 | 606 |
| 821 if (any_thread().immediate_incoming_queue.empty()) | 607 if (any_thread().immediate_incoming_queue.empty()) |
| 822 return true; | 608 return true; |
| 823 | 609 |
| 824 return any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 610 return any_thread().immediate_incoming_queue.front().enqueue_order() > |
| 825 main_thread_only().current_fence; | 611 main_thread_only().current_fence; |
| 826 } | 612 } |
| 827 | 613 |
| 828 // static | 614 // static |
| 829 void TaskQueueImpl::QueueAsValueInto(const ComparatorQueue& queue, | 615 void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue, |
| 830 base::trace_event::TracedValue* state) { | 616 base::trace_event::TracedValue* state) { |
| 831 for (const Task& task : queue) { | 617 // Remove const to search |queue| in the destructive manner. Restore the |
| 832 TaskAsValueInto(task, state); | 618 // content from |visited| later. |
| 619 std::queue<Task>* mutable_queue = const_cast<std::queue<Task>*>(&queue); | |
| 620 std::queue<Task> visited; | |
| 621 while (!mutable_queue->empty()) { | |
| 622 TaskAsValueInto(mutable_queue->front(), state); | |
| 623 visited.push(std::move(mutable_queue->front())); | |
| 624 mutable_queue->pop(); | |
| 833 } | 625 } |
| 626 *mutable_queue = std::move(visited); | |
| 834 } | 627 } |
| 835 | 628 |
| 836 // static | 629 // static |
| 837 void TaskQueueImpl::QueueAsValueInto(const DelayedRunTimeQueue& queue, | 630 void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue, |
| 838 base::trace_event::TracedValue* state) { | 631 base::trace_event::TracedValue* state) { |
| 839 for (const Task& task : queue) { | 632 // Remove const to search |queue| in the destructive manner. Restore the |
| 840 TaskAsValueInto(task, state); | 633 // content from |visited| later. |
| 634 std::priority_queue<Task>* mutable_queue = | |
| 635 const_cast<std::priority_queue<Task>*>(&queue); | |
| 636 std::priority_queue<Task> visited; | |
| 637 while (!mutable_queue->empty()) { | |
| 638 TaskAsValueInto(mutable_queue->top(), state); | |
| 639 visited.push(std::move(const_cast<Task&>(mutable_queue->top()))); | |
| 640 mutable_queue->pop(); | |
| 841 } | 641 } |
| 642 *mutable_queue = std::move(visited); | |
| 842 } | 643 } |
| 843 | 644 |
| 844 // static | 645 // static |
| 845 void TaskQueueImpl::TaskAsValueInto(const Task& task, | 646 void TaskQueueImpl::TaskAsValueInto(const Task& task, |
| 846 base::trace_event::TracedValue* state) { | 647 base::trace_event::TracedValue* state) { |
| 847 state->BeginDictionary(); | 648 state->BeginDictionary(); |
| 848 state->SetString("posted_from", task.posted_from.ToString()); | 649 state->SetString("posted_from", task.posted_from.ToString()); |
| 849 #ifndef NDEBUG | 650 #ifndef NDEBUG |
| 850 if (task.enqueue_order_set()) | 651 if (task.enqueue_order_set()) |
| 851 state->SetInteger("enqueue_order", task.enqueue_order()); | 652 state->SetInteger("enqueue_order", task.enqueue_order()); |
| 852 #else | 653 #else |
| 853 state->SetInteger("enqueue_order", task.enqueue_order()); | 654 state->SetInteger("enqueue_order", task.enqueue_order()); |
| 854 #endif | 655 #endif |
| 855 state->SetInteger("sequence_num", task.sequence_num); | 656 state->SetInteger("sequence_num", task.sequence_num); |
| 856 state->SetBoolean("nestable", task.nestable); | 657 state->SetBoolean("nestable", task.nestable); |
| 857 state->SetBoolean("is_high_res", task.is_high_res); | 658 state->SetBoolean("is_high_res", task.is_high_res); |
| 659 state->SetBoolean("is_cancelled", task.task.IsCancelled()); | |
| 858 state->SetDouble( | 660 state->SetDouble( |
| 859 "delayed_run_time", | 661 "delayed_run_time", |
| 860 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); | 662 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); |
| 861 state->EndDictionary(); | 663 state->EndDictionary(); |
| 862 } | 664 } |
| 863 | 665 |
| 864 } // namespace internal | 666 } // namespace internal |
| 865 } // namespace scheduler | 667 } // namespace scheduler |
| 866 } // namespace blink | 668 } // namespace blink |
| OLD | NEW |