| 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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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()); |
| 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 base::TimeTicks time_after_task; |
| 245 switch (ProcessTaskFromWorkQueue(work_queue, lazy_now, &time_after_task)) { |
| 243 case ProcessTaskResult::DEFERRED: | 246 case ProcessTaskResult::DEFERRED: |
| 244 // If a task was deferred, try again with another task. | 247 // If a task was deferred, try again with another task. |
| 245 continue; | 248 continue; |
| 246 case ProcessTaskResult::EXECUTED: | 249 case ProcessTaskResult::EXECUTED: |
| 247 break; | 250 break; |
| 248 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: | 251 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: |
| 249 return; // The TaskQueueManager got deleted, we must bail out. | 252 return; // The TaskQueueManager got deleted, we must bail out. |
| 250 } | 253 } |
| 251 | 254 |
| 252 work_queue = nullptr; // The queue may have been unregistered. | 255 work_queue = nullptr; // The queue may have been unregistered. |
| 253 | 256 |
| 254 UpdateWorkQueues(lazy_now); | 257 lazy_now = time_after_task.is_null() ? real_time_domain()->CreateLazyNow() |
| 258 : LazyNow(time_after_task); |
| 259 UpdateWorkQueues(&lazy_now); |
| 255 | 260 |
| 256 // Only run a single task per batch in nested run loops so that we can | 261 // 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(). | 262 // properly exit the nested loop when someone calls RunLoop::Quit(). |
| 258 if (delegate_->IsNested()) | 263 if (delegate_->IsNested()) |
| 259 break; | 264 break; |
| 260 } | 265 } |
| 261 | 266 |
| 262 main_thread_pending_wakeups_.erase(base::TimeTicks()); | 267 main_thread_pending_wakeups_.erase(base::TimeTicks()); |
| 263 | 268 |
| 264 // TODO(alexclarke): Consider refactoring the above loop to terminate only | 269 // 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 | 270 // when there's no more work left to be done, rather than posting a |
| 266 // continuation task. | 271 // continuation task. |
| 267 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) | 272 base::Optional<base::TimeDelta> next_delay = |
| 273 ComputeDelayTillNextTask(&lazy_now); |
| 274 |
| 275 if (!next_delay) |
| 276 return; |
| 277 |
| 278 base::TimeDelta delay = next_delay.value(); |
| 279 if (delay.is_zero()) { |
| 268 MaybeScheduleImmediateWork(FROM_HERE); | 280 MaybeScheduleImmediateWork(FROM_HERE); |
| 281 } else { |
| 282 MaybeScheduleDelayedWork(FROM_HERE, lazy_now.Now(), delay); |
| 283 } |
| 269 } | 284 } |
| 270 | 285 |
| 271 bool TaskQueueManager::TryAdvanceTimeDomains() { | 286 base::Optional<base::TimeDelta> TaskQueueManager::ComputeDelayTillNextTask( |
| 272 bool can_advance = false; | 287 LazyNow* lazy_now) { |
| 288 // If the selector has non-empty queues we trivially know there is immediate |
| 289 // work to be done. |
| 290 if (!selector_.EnabledWorkQueuesEmpty()) |
| 291 return base::TimeDelta(); |
| 292 |
| 293 // Otherwise we need to find the shortest delay, if any. |
| 294 base::Optional<base::TimeDelta> next_continuation; |
| 273 for (TimeDomain* time_domain : time_domains_) { | 295 for (TimeDomain* time_domain : time_domains_) { |
| 274 can_advance |= time_domain->MaybeAdvanceTime(); | 296 base::Optional<base::TimeDelta> continuation = |
| 297 time_domain->DelayTillNextTask(lazy_now); |
| 298 if (!continuation) |
| 299 continue; |
| 300 if (!next_continuation || next_continuation.value() > continuation.value()) |
| 301 next_continuation = continuation; |
| 275 } | 302 } |
| 276 return can_advance; | 303 return next_continuation; |
| 277 } | 304 } |
| 278 | 305 |
| 279 bool TaskQueueManager::SelectWorkQueueToService( | 306 bool TaskQueueManager::SelectWorkQueueToService( |
| 280 internal::WorkQueue** out_work_queue) { | 307 internal::WorkQueue** out_work_queue) { |
| 281 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); | 308 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); |
| 282 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 309 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 283 disabled_by_default_tracing_category_, "TaskQueueManager", this, | 310 disabled_by_default_tracing_category_, "TaskQueueManager", this, |
| 284 AsValueWithSelectorResult(should_run, *out_work_queue)); | 311 AsValueWithSelectorResult(should_run, *out_work_queue)); |
| 285 return should_run; | 312 return should_run; |
| 286 } | 313 } |
| 287 | 314 |
| 288 void TaskQueueManager::DidQueueTask( | 315 void TaskQueueManager::DidQueueTask( |
| 289 const internal::TaskQueueImpl::Task& pending_task) { | 316 const internal::TaskQueueImpl::Task& pending_task) { |
| 290 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); | 317 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); |
| 291 } | 318 } |
| 292 | 319 |
| 293 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( | 320 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( |
| 294 internal::WorkQueue* work_queue, | 321 internal::WorkQueue* work_queue, |
| 295 LazyNow* lazy_now) { | 322 LazyNow time_before_task, |
| 323 base::TimeTicks* time_after_task) { |
| 296 DCHECK(main_thread_checker_.CalledOnValidThread()); | 324 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 297 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); | 325 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); |
| 298 internal::TaskQueueImpl::Task pending_task = | 326 internal::TaskQueueImpl::Task pending_task = |
| 299 work_queue->TakeTaskFromWorkQueue(); | 327 work_queue->TakeTaskFromWorkQueue(); |
| 300 | 328 |
| 301 // It's possible the task was canceled, if so bail out. | 329 // It's possible the task was canceled, if so bail out. |
| 302 if (pending_task.task.IsCancelled()) | 330 if (pending_task.task.IsCancelled()) |
| 303 return ProcessTaskResult::EXECUTED; | 331 return ProcessTaskResult::EXECUTED; |
| 304 | 332 |
| 305 internal::TaskQueueImpl* queue = work_queue->task_queue(); | 333 internal::TaskQueueImpl* queue = work_queue->task_queue(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 325 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", | 353 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", |
| 326 pending_task); | 354 pending_task); |
| 327 if (queue->GetShouldNotifyObservers()) { | 355 if (queue->GetShouldNotifyObservers()) { |
| 328 for (auto& observer : task_observers_) | 356 for (auto& observer : task_observers_) |
| 329 observer.WillProcessTask(pending_task); | 357 observer.WillProcessTask(pending_task); |
| 330 queue->NotifyWillProcessTask(pending_task); | 358 queue->NotifyWillProcessTask(pending_task); |
| 331 | 359 |
| 332 bool notify_time_observers = | 360 bool notify_time_observers = |
| 333 !delegate_->IsNested() && task_time_observers_.might_have_observers(); | 361 !delegate_->IsNested() && task_time_observers_.might_have_observers(); |
| 334 if (notify_time_observers) { | 362 if (notify_time_observers) { |
| 335 task_start_time = MonotonicTimeInSeconds(lazy_now->Now()); | 363 task_start_time = MonotonicTimeInSeconds(time_before_task.Now()); |
| 336 for (auto& observer : task_time_observers_) | 364 for (auto& observer : task_time_observers_) |
| 337 observer.willProcessTask(queue, task_start_time); | 365 observer.willProcessTask(queue, task_start_time); |
| 338 } | 366 } |
| 339 } | 367 } |
| 340 | 368 |
| 341 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue", | 369 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue", |
| 342 queue->GetName()); | 370 queue->GetName()); |
| 343 // NOTE when TaskQueues get unregistered a reference ends up getting retained | 371 // NOTE when TaskQueues get unregistered a reference ends up getting retained |
| 344 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means | 372 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means |
| 345 // we are OK to use raw pointers here. | 373 // we are OK to use raw pointers here. |
| 346 internal::TaskQueueImpl* prev_executing_task_queue = | 374 internal::TaskQueueImpl* prev_executing_task_queue = |
| 347 currently_executing_task_queue_; | 375 currently_executing_task_queue_; |
| 348 currently_executing_task_queue_ = queue; | 376 currently_executing_task_queue_ = queue; |
| 349 task_annotator_.RunTask("TaskQueueManager::PostTask", &pending_task); | 377 task_annotator_.RunTask("TaskQueueManager::PostTask", &pending_task); |
| 350 // Detect if the TaskQueueManager just got deleted. If this happens we must | 378 // Detect if the TaskQueueManager just got deleted. If this happens we must |
| 351 // not access any member variables after this point. | 379 // not access any member variables after this point. |
| 352 if (protect->HasOneRef()) | 380 if (protect->HasOneRef()) |
| 353 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED; | 381 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED; |
| 354 | 382 |
| 355 currently_executing_task_queue_ = prev_executing_task_queue; | 383 currently_executing_task_queue_ = prev_executing_task_queue; |
| 356 | 384 |
| 357 *lazy_now = real_time_domain()->CreateLazyNow(); | |
| 358 | 385 |
| 359 if (queue->GetShouldNotifyObservers()) { | 386 if (queue->GetShouldNotifyObservers()) { |
| 360 if (task_start_time) { | 387 if (task_start_time) { |
| 361 double task_end_time = MonotonicTimeInSeconds(lazy_now->Now()); | 388 *time_after_task = real_time_domain()->Now(); |
| 389 double task_end_time = MonotonicTimeInSeconds(*time_after_task); |
| 362 for (auto& observer : task_time_observers_) | 390 for (auto& observer : task_time_observers_) |
| 363 observer.didProcessTask(queue, task_start_time, task_end_time); | 391 observer.didProcessTask(queue, task_start_time, task_end_time); |
| 364 } | 392 } |
| 365 | 393 |
| 366 for (auto& observer : task_observers_) | 394 for (auto& observer : task_observers_) |
| 367 observer.DidProcessTask(pending_task); | 395 observer.DidProcessTask(pending_task); |
| 368 queue->NotifyDidProcessTask(pending_task); | 396 queue->NotifyDidProcessTask(pending_task); |
| 369 } | 397 } |
| 370 | 398 |
| 371 return ProcessTaskResult::EXECUTED; | 399 return ProcessTaskResult::EXECUTED; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 402 DCHECK(main_thread_checker_.CalledOnValidThread()); | 430 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 403 task_observers_.AddObserver(task_observer); | 431 task_observers_.AddObserver(task_observer); |
| 404 } | 432 } |
| 405 | 433 |
| 406 void TaskQueueManager::RemoveTaskObserver( | 434 void TaskQueueManager::RemoveTaskObserver( |
| 407 base::MessageLoop::TaskObserver* task_observer) { | 435 base::MessageLoop::TaskObserver* task_observer) { |
| 408 DCHECK(main_thread_checker_.CalledOnValidThread()); | 436 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 409 task_observers_.RemoveObserver(task_observer); | 437 task_observers_.RemoveObserver(task_observer); |
| 410 } | 438 } |
| 411 | 439 |
| 412 void TaskQueueManager::AddTaskTimeObserver(TaskTimeObserver* task_time_observer)
{ | 440 void TaskQueueManager::AddTaskTimeObserver( |
| 441 TaskTimeObserver* task_time_observer) { |
| 413 DCHECK(main_thread_checker_.CalledOnValidThread()); | 442 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 414 task_time_observers_.AddObserver(task_time_observer); | 443 task_time_observers_.AddObserver(task_time_observer); |
| 415 } | 444 } |
| 416 | 445 |
| 417 void TaskQueueManager::RemoveTaskTimeObserver( | 446 void TaskQueueManager::RemoveTaskTimeObserver( |
| 418 TaskTimeObserver* task_time_observer) { | 447 TaskTimeObserver* task_time_observer) { |
| 419 DCHECK(main_thread_checker_.CalledOnValidThread()); | 448 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 420 task_time_observers_.RemoveObserver(task_time_observer); | 449 task_time_observers_.RemoveObserver(task_time_observer); |
| 421 } | 450 } |
| 422 | 451 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { | 528 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { |
| 500 TimeDomain* time_domain = queue->GetTimeDomain(); | 529 TimeDomain* time_domain = queue->GetTimeDomain(); |
| 501 if (time_domain_now.find(time_domain) == time_domain_now.end()) | 530 if (time_domain_now.find(time_domain) == time_domain_now.end()) |
| 502 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); | 531 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); |
| 503 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); | 532 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); |
| 504 } | 533 } |
| 505 } | 534 } |
| 506 | 535 |
| 507 } // namespace scheduler | 536 } // namespace scheduler |
| 508 } // namespace blink | 537 } // namespace blink |
| OLD | NEW |