Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_manager.h" | 5 #include "platform/scheduler/base/task_queue_manager.h" |
| 6 | 6 |
| 7 #include <queue> | 7 #include <queue> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 observer_->OnUnregisterTaskQueue(task_queue); | 140 observer_->OnUnregisterTaskQueue(task_queue); |
| 141 | 141 |
| 142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being | 142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being |
| 143 // freed while any of our structures hold hold a raw pointer to it. | 143 // freed while any of our structures hold hold a raw pointer to it. |
| 144 queues_to_delete_.insert(task_queue); | 144 queues_to_delete_.insert(task_queue); |
| 145 queues_.erase(task_queue); | 145 queues_.erase(task_queue); |
| 146 | 146 |
| 147 selector_.RemoveQueue(task_queue.get()); | 147 selector_.RemoveQueue(task_queue.get()); |
| 148 } | 148 } |
| 149 | 149 |
| 150 void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) { | 150 void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) { |
| 151 TRACE_EVENT0(disabled_by_default_tracing_category_, | 151 TRACE_EVENT0(disabled_by_default_tracing_category_, |
| 152 "TaskQueueManager::UpdateWorkQueues"); | 152 "TaskQueueManager::UpdateWorkQueues"); |
| 153 | 153 |
| 154 for (TimeDomain* time_domain : time_domains_) { | 154 for (TimeDomain* time_domain : time_domains_) { |
| 155 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() | 155 if (time_domain == real_time_domain_.get()) { |
| 156 ? lazy_now | 156 time_domain->UpdateWorkQueues(lazy_now); |
| 157 : time_domain->CreateLazyNow(); | 157 } else { |
| 158 time_domain->UpdateWorkQueues(lazy_now_in_domain); | 158 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow(); |
| 159 time_domain->UpdateWorkQueues(&time_domain_lazy_now); | |
| 160 } | |
| 159 } | 161 } |
| 160 } | 162 } |
| 161 | 163 |
| 162 void TaskQueueManager::OnBeginNestedMessageLoop() { | 164 void TaskQueueManager::OnBeginNestedMessageLoop() { |
| 163 // We just entered a nested message loop, make sure there's a DoWork posted or | 165 // We just entered a nested message loop, make sure there's a DoWork posted or |
| 164 // the system will grind to a halt. | 166 // the system will grind to a halt. |
| 165 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); | 167 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); |
| 166 } | 168 } |
| 167 | 169 |
| 168 void TaskQueueManager::MaybeScheduleImmediateWork( | 170 void TaskQueueManager::MaybeScheduleImmediateWork( |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 base::AutoLock lock(other_thread_lock_); | 226 base::AutoLock lock(other_thread_lock_); |
| 225 other_thread_pending_wakeup_ = false; | 227 other_thread_pending_wakeup_ = false; |
| 226 } | 228 } |
| 227 | 229 |
| 228 // Posting a DoWork while a DoWork is running leads to spurious DoWorks. | 230 // Posting a DoWork while a DoWork is running leads to spurious DoWorks. |
| 229 main_thread_pending_wakeups_.insert(base::TimeTicks()); | 231 main_thread_pending_wakeups_.insert(base::TimeTicks()); |
| 230 | 232 |
| 231 if (!delegate_->IsNested()) | 233 if (!delegate_->IsNested()) |
| 232 queues_to_delete_.clear(); | 234 queues_to_delete_.clear(); |
| 233 | 235 |
| 234 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); | 236 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); |
|
Sami
2017/01/18 18:45:57
General comment re: |lazy_now|, not sure if it con
| |
| 235 UpdateWorkQueues(lazy_now); | 237 UpdateWorkQueues(&lazy_now); |
| 236 | 238 |
| 237 for (int i = 0; i < work_batch_size_; i++) { | 239 for (int i = 0; i < work_batch_size_; i++) { |
| 238 internal::WorkQueue* work_queue; | 240 internal::WorkQueue* work_queue; |
| 239 if (!SelectWorkQueueToService(&work_queue)) | 241 if (!SelectWorkQueueToService(&work_queue)) |
| 240 break; | 242 break; |
| 241 | 243 |
| 242 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) { | 244 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) { |
| 243 case ProcessTaskResult::DEFERRED: | 245 case ProcessTaskResult::DEFERRED: |
| 244 // If a task was deferred, try again with another task. | 246 // If a task was deferred, try again with another task. |
| 245 continue; | 247 continue; |
| 246 case ProcessTaskResult::EXECUTED: | 248 case ProcessTaskResult::EXECUTED: |
| 247 break; | 249 break; |
| 248 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: | 250 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: |
| 249 return; // The TaskQueueManager got deleted, we must bail out. | 251 return; // The TaskQueueManager got deleted, we must bail out. |
| 250 } | 252 } |
| 251 | 253 |
| 252 work_queue = nullptr; // The queue may have been unregistered. | 254 work_queue = nullptr; // The queue may have been unregistered. |
| 253 | 255 |
| 254 UpdateWorkQueues(lazy_now); | 256 UpdateWorkQueues(&lazy_now); |
| 255 | 257 |
| 256 // Only run a single task per batch in nested run loops so that we can | 258 // Only run a single task per batch in nested run loops so that we can |
| 257 // properly exit the nested loop when someone calls RunLoop::Quit(). | 259 // properly exit the nested loop when someone calls RunLoop::Quit(). |
| 258 if (delegate_->IsNested()) | 260 if (delegate_->IsNested()) |
| 259 break; | 261 break; |
| 260 } | 262 } |
| 261 | 263 |
| 262 main_thread_pending_wakeups_.erase(base::TimeTicks()); | 264 main_thread_pending_wakeups_.erase(base::TimeTicks()); |
| 263 | 265 |
| 264 // TODO(alexclarke): Consider refactoring the above loop to terminate only | 266 // TODO(alexclarke): Consider refactoring the above loop to terminate only |
| 265 // when there's no more work left to be done, rather than posting a | 267 // when there's no more work left to be done, rather than posting a |
| 266 // continuation task. | 268 // continuation task. |
| 267 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) | 269 base::Optional<base::TimeDelta> next_delay = |
| 270 ComputeDelayTillNextTask(&lazy_now); | |
| 271 | |
| 272 if (!next_delay) | |
| 273 return; | |
| 274 | |
| 275 base::TimeDelta delay = next_delay.value(); | |
| 276 if (delay.is_zero()) { | |
| 268 MaybeScheduleImmediateWork(FROM_HERE); | 277 MaybeScheduleImmediateWork(FROM_HERE); |
| 278 } else { | |
| 279 MaybeScheduleDelayedWork(FROM_HERE, lazy_now.Now(), delay); | |
| 280 } | |
| 269 } | 281 } |
| 270 | 282 |
| 271 bool TaskQueueManager::TryAdvanceTimeDomains() { | 283 base::Optional<base::TimeDelta> TaskQueueManager::ComputeDelayTillNextTask( |
| 272 bool can_advance = false; | 284 LazyNow* lazy_now) { |
| 285 // If the selector has non-empty queues we trivially know there is immediate | |
| 286 // work to be done. | |
| 287 if (!selector_.EnabledWorkQueuesEmpty()) | |
| 288 return base::TimeDelta(); | |
| 289 | |
| 290 // Otherwise we need to find the shortest delay, if any. | |
| 291 base::Optional<base::TimeDelta> next_continuation; | |
| 273 for (TimeDomain* time_domain : time_domains_) { | 292 for (TimeDomain* time_domain : time_domains_) { |
| 274 can_advance |= time_domain->MaybeAdvanceTime(); | 293 base::Optional<base::TimeDelta> continuation = |
| 294 time_domain->DelayTillNextTask(lazy_now); | |
| 295 if (!continuation) | |
| 296 continue; | |
| 297 if (!next_continuation || next_continuation.value() > continuation.value()) | |
| 298 next_continuation = continuation; | |
| 275 } | 299 } |
| 276 return can_advance; | 300 return next_continuation; |
| 277 } | 301 } |
| 278 | 302 |
| 279 bool TaskQueueManager::SelectWorkQueueToService( | 303 bool TaskQueueManager::SelectWorkQueueToService( |
| 280 internal::WorkQueue** out_work_queue) { | 304 internal::WorkQueue** out_work_queue) { |
| 281 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); | 305 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); |
| 282 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 306 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 283 disabled_by_default_tracing_category_, "TaskQueueManager", this, | 307 disabled_by_default_tracing_category_, "TaskQueueManager", this, |
| 284 AsValueWithSelectorResult(should_run, *out_work_queue)); | 308 AsValueWithSelectorResult(should_run, *out_work_queue)); |
| 285 return should_run; | 309 return should_run; |
| 286 } | 310 } |
| 287 | 311 |
| 288 void TaskQueueManager::DidQueueTask( | 312 void TaskQueueManager::DidQueueTask( |
| 289 const internal::TaskQueueImpl::Task& pending_task) { | 313 const internal::TaskQueueImpl::Task& pending_task) { |
| 290 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); | 314 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); |
| 291 } | 315 } |
| 292 | 316 |
| 293 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( | 317 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( |
| 294 internal::WorkQueue* work_queue, | 318 internal::WorkQueue* work_queue, |
| 295 LazyNow* lazy_now) { | 319 LazyNow* lazy_now) { |
| 296 DCHECK(main_thread_checker_.CalledOnValidThread()); | 320 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 297 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); | 321 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); |
| 298 internal::TaskQueueImpl::Task pending_task = | 322 internal::TaskQueueImpl::Task pending_task = |
| 299 work_queue->TakeTaskFromWorkQueue(); | 323 work_queue->TakeTaskFromWorkQueue(); |
| 300 | 324 |
| 301 // It's possible the task was canceled, if so bail out. | 325 // It's possible the task was canceled, if so bail out. |
| 302 if (pending_task.task.IsCancelled()) | 326 if (pending_task.task.IsCancelled()) { |
| 327 *lazy_now = real_time_domain()->CreateLazyNow(); | |
|
Sami
2017/01/18 18:45:57
We were assuming that operations not involving run
alex clarke (OOO till 29th)
2017/01/19 08:56:10
Yes because task selection takes time. Constructi
Sami
2017/01/19 12:01:00
Yeah, actually I think we could just create one at
Sami
2017/01/19 12:10:15
Offline: turns out we can't because of time observ
alex clarke (OOO till 29th)
2017/01/19 14:25:02
Done.
| |
| 303 return ProcessTaskResult::EXECUTED; | 328 return ProcessTaskResult::EXECUTED; |
| 329 } | |
| 304 | 330 |
| 305 internal::TaskQueueImpl* queue = work_queue->task_queue(); | 331 internal::TaskQueueImpl* queue = work_queue->task_queue(); |
| 306 if (queue->GetQuiescenceMonitored()) | 332 if (queue->GetQuiescenceMonitored()) |
| 307 task_was_run_on_quiescence_monitored_queue_ = true; | 333 task_was_run_on_quiescence_monitored_queue_ = true; |
| 308 | 334 |
| 309 if (!pending_task.nestable && delegate_->IsNested()) { | 335 if (!pending_task.nestable && delegate_->IsNested()) { |
| 310 // Defer non-nestable work to the main task runner. NOTE these tasks can be | 336 // Defer non-nestable work to the main task runner. NOTE these tasks can be |
| 311 // arbitrarily delayed so the additional delay should not be a problem. | 337 // arbitrarily delayed so the additional delay should not be a problem. |
| 312 // TODO(skyostil): Figure out a way to not forget which task queue the | 338 // TODO(skyostil): Figure out a way to not forget which task queue the |
| 313 // task is associated with. See http://crbug.com/522843. | 339 // task is associated with. See http://crbug.com/522843. |
| 314 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once | 340 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once |
| 315 // TaskRunners have migrated to OnceClosure. | 341 // TaskRunners have migrated to OnceClosure. |
| 316 delegate_->PostNonNestableTask( | 342 delegate_->PostNonNestableTask( |
| 317 pending_task.posted_from, | 343 pending_task.posted_from, |
| 318 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task))); | 344 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task))); |
| 345 *lazy_now = real_time_domain()->CreateLazyNow(); | |
| 319 return ProcessTaskResult::DEFERRED; | 346 return ProcessTaskResult::DEFERRED; |
| 320 } | 347 } |
| 321 | 348 |
| 322 MaybeRecordTaskDelayHistograms(pending_task, queue); | 349 MaybeRecordTaskDelayHistograms(pending_task, queue); |
| 323 | 350 |
| 324 double task_start_time = 0; | 351 double task_start_time = 0; |
| 325 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", | 352 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", |
| 326 pending_task); | 353 pending_task); |
| 327 if (queue->GetShouldNotifyObservers()) { | 354 if (queue->GetShouldNotifyObservers()) { |
| 328 for (auto& observer : task_observers_) | 355 for (auto& observer : task_observers_) |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { | 526 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { |
| 500 TimeDomain* time_domain = queue->GetTimeDomain(); | 527 TimeDomain* time_domain = queue->GetTimeDomain(); |
| 501 if (time_domain_now.find(time_domain) == time_domain_now.end()) | 528 if (time_domain_now.find(time_domain) == time_domain_now.end()) |
| 502 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); | 529 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); |
| 503 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); | 530 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); |
| 504 } | 531 } |
| 505 } | 532 } |
| 506 | 533 |
| 507 } // namespace scheduler | 534 } // namespace scheduler |
| 508 } // namespace blink | 535 } // namespace blink |
| OLD | NEW |