| 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 "components/scheduler/base/task_queue_manager.h" | 5 #include "components/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" |
| 11 #include "base/time/default_tick_clock.h" | |
| 12 #include "components/scheduler/base/lazy_now.h" | 11 #include "components/scheduler/base/lazy_now.h" |
| 13 #include "components/scheduler/base/nestable_single_thread_task_runner.h" | 12 #include "components/scheduler/base/nestable_single_thread_task_runner.h" |
| 14 #include "components/scheduler/base/task_queue_impl.h" | 13 #include "components/scheduler/base/task_queue_impl.h" |
| 15 #include "components/scheduler/base/task_queue_selector.h" | 14 #include "components/scheduler/base/task_queue_selector.h" |
| 16 #include "components/scheduler/base/task_queue_sets.h" | 15 #include "components/scheduler/base/task_queue_sets.h" |
| 17 | 16 |
| 18 namespace { | 17 namespace { |
| 19 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); | 18 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); |
| 20 } | 19 } |
| 21 | 20 |
| 22 namespace scheduler { | 21 namespace scheduler { |
| 23 | 22 |
| 24 TaskQueueManager::TaskQueueManager( | 23 TaskQueueManager::TaskQueueManager( |
| 25 scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner, | 24 scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner, |
| 26 const char* tracing_category, | 25 const char* tracing_category, |
| 27 const char* disabled_by_default_tracing_category, | 26 const char* disabled_by_default_tracing_category, |
| 28 const char* disabled_by_default_verbose_tracing_category) | 27 const char* disabled_by_default_verbose_tracing_category) |
| 29 : main_task_runner_(main_task_runner), | 28 : main_task_runner_(main_task_runner), |
| 30 task_was_run_on_quiescence_monitored_queue_(false), | 29 task_was_run_on_quiescence_monitored_queue_(false), |
| 31 pending_dowork_count_(0), | 30 pending_dowork_count_(0), |
| 32 work_batch_size_(1), | 31 work_batch_size_(1), |
| 33 time_source_(new base::DefaultTickClock), | |
| 34 tracing_category_(tracing_category), | 32 tracing_category_(tracing_category), |
| 35 disabled_by_default_tracing_category_( | 33 disabled_by_default_tracing_category_( |
| 36 disabled_by_default_tracing_category), | 34 disabled_by_default_tracing_category), |
| 37 disabled_by_default_verbose_tracing_category_( | 35 disabled_by_default_verbose_tracing_category_( |
| 38 disabled_by_default_verbose_tracing_category), | 36 disabled_by_default_verbose_tracing_category), |
| 39 observer_(nullptr), | 37 observer_(nullptr), |
| 40 deletion_sentinel_(new DeletionSentinel()), | 38 deletion_sentinel_(new DeletionSentinel()), |
| 41 weak_factory_(this) { | 39 weak_factory_(this) { |
| 42 DCHECK(main_task_runner->RunsTasksOnCurrentThread()); | 40 DCHECK(main_task_runner->RunsTasksOnCurrentThread()); |
| 43 TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, | 41 TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 newly_updatable_.pop_back(); | 166 newly_updatable_.pop_back(); |
| 169 } | 167 } |
| 170 } | 168 } |
| 171 | 169 |
| 172 void TaskQueueManager::UpdateWorkQueues( | 170 void TaskQueueManager::UpdateWorkQueues( |
| 173 bool should_trigger_wakeup, | 171 bool should_trigger_wakeup, |
| 174 const internal::TaskQueueImpl::Task* previous_task) { | 172 const internal::TaskQueueImpl::Task* previous_task) { |
| 175 DCHECK(main_thread_checker_.CalledOnValidThread()); | 173 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 176 TRACE_EVENT0(disabled_by_default_tracing_category_, | 174 TRACE_EVENT0(disabled_by_default_tracing_category_, |
| 177 "TaskQueueManager::UpdateWorkQueues"); | 175 "TaskQueueManager::UpdateWorkQueues"); |
| 178 internal::LazyNow lazy_now(this); | 176 internal::LazyNow lazy_now(tick_clock()); |
| 179 | 177 |
| 180 // Move any ready delayed tasks into the incomming queues. | 178 // Move any ready delayed tasks into the incomming queues. |
| 181 WakeupReadyDelayedQueues(&lazy_now); | 179 WakeupReadyDelayedQueues(&lazy_now); |
| 182 | 180 |
| 183 MoveNewlyUpdatableQueuesIntoUpdatableQueueSet(); | 181 MoveNewlyUpdatableQueuesIntoUpdatableQueueSet(); |
| 184 | 182 |
| 185 auto iter = updatable_queue_set_.begin(); | 183 auto iter = updatable_queue_set_.begin(); |
| 186 while (iter != updatable_queue_set_.end()) { | 184 while (iter != updatable_queue_set_.end()) { |
| 187 internal::TaskQueueImpl* queue = *iter++; | 185 internal::TaskQueueImpl* queue = *iter++; |
| 188 // NOTE Update work queue may erase itself from |updatable_queue_set_|. | 186 // NOTE Update work queue may erase itself from |updatable_queue_set_|. |
| 189 // This is fine, erasing an element won't invalidate any interator, as long | 187 // This is fine, erasing an element won't invalidate any interator, as long |
| 190 // as the iterator isn't the element being delated. | 188 // as the iterator isn't the element being delated. |
| 191 if (queue->work_queue().empty()) | 189 if (queue->work_queue().empty()) |
| 192 queue->UpdateWorkQueue(&lazy_now, should_trigger_wakeup, previous_task); | 190 queue->UpdateWorkQueue(&lazy_now, should_trigger_wakeup, previous_task); |
| 193 } | 191 } |
| 194 } | 192 } |
| 195 | 193 |
| 196 void TaskQueueManager::ScheduleDelayedWorkTask( | 194 void TaskQueueManager::ScheduleDelayedWorkTask( |
| 197 scoped_refptr<internal::TaskQueueImpl> queue, | 195 scoped_refptr<internal::TaskQueueImpl> queue, |
| 198 base::TimeTicks delayed_run_time) { | 196 base::TimeTicks delayed_run_time) { |
| 199 internal::LazyNow lazy_now(this); | 197 internal::LazyNow lazy_now(tick_clock()); |
| 200 ScheduleDelayedWork(queue.get(), delayed_run_time, &lazy_now); | 198 ScheduleDelayedWork(queue.get(), delayed_run_time, &lazy_now); |
| 201 } | 199 } |
| 202 | 200 |
| 203 void TaskQueueManager::ScheduleDelayedWork(internal::TaskQueueImpl* queue, | 201 void TaskQueueManager::ScheduleDelayedWork(internal::TaskQueueImpl* queue, |
| 204 base::TimeTicks delayed_run_time, | 202 base::TimeTicks delayed_run_time, |
| 205 internal::LazyNow* lazy_now) { | 203 internal::LazyNow* lazy_now) { |
| 206 if (!main_task_runner_->BelongsToCurrentThread()) { | 204 if (!main_task_runner_->BelongsToCurrentThread()) { |
| 207 // NOTE posting a delayed task from a different thread is not expected to be | 205 // NOTE posting a delayed task from a different thread is not expected to be |
| 208 // common. This pathway is less optimal than perhaps it could be because | 206 // common. This pathway is less optimal than perhaps it could be because |
| 209 // it causes two main thread tasks to be run. Should this assumption prove | 207 // it causes two main thread tasks to be run. Should this assumption prove |
| (...skipping 15 matching lines...) Expand all Loading... |
| 225 main_task_runner_->PostDelayedTask(FROM_HERE, delayed_queue_wakeup_closure_, | 223 main_task_runner_->PostDelayedTask(FROM_HERE, delayed_queue_wakeup_closure_, |
| 226 delay); | 224 delay); |
| 227 } | 225 } |
| 228 delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue)); | 226 delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue)); |
| 229 } | 227 } |
| 230 | 228 |
| 231 void TaskQueueManager::DelayedDoWork() { | 229 void TaskQueueManager::DelayedDoWork() { |
| 232 DCHECK(main_thread_checker_.CalledOnValidThread()); | 230 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 233 | 231 |
| 234 { | 232 { |
| 235 internal::LazyNow lazy_now(this); | 233 internal::LazyNow lazy_now(tick_clock()); |
| 236 WakeupReadyDelayedQueues(&lazy_now); | 234 WakeupReadyDelayedQueues(&lazy_now); |
| 237 } | 235 } |
| 238 | 236 |
| 239 DoWork(false); | 237 DoWork(false); |
| 240 } | 238 } |
| 241 | 239 |
| 242 void TaskQueueManager::WakeupReadyDelayedQueues(internal::LazyNow* lazy_now) { | 240 void TaskQueueManager::WakeupReadyDelayedQueues(internal::LazyNow* lazy_now) { |
| 243 // Wake up any queues with pending delayed work. Note std::multipmap stores | 241 // Wake up any queues with pending delayed work. Note std::multipmap stores |
| 244 // the elements sorted by key, so the begin() iterator points to the earliest | 242 // the elements sorted by key, so the begin() iterator points to the earliest |
| 245 // queue to wakeup. | 243 // queue to wakeup. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 | 310 |
| 313 // Only run a single task per batch in nested run loops so that we can | 311 // Only run a single task per batch in nested run loops so that we can |
| 314 // properly exit the nested loop when someone calls RunLoop::Quit(). | 312 // properly exit the nested loop when someone calls RunLoop::Quit(). |
| 315 if (main_task_runner_->IsNested()) | 313 if (main_task_runner_->IsNested()) |
| 316 break; | 314 break; |
| 317 } | 315 } |
| 318 | 316 |
| 319 // TODO(alexclarke): Consider refactoring the above loop to terminate only | 317 // TODO(alexclarke): Consider refactoring the above loop to terminate only |
| 320 // when there's no more work left to be done, rather than posting a | 318 // when there's no more work left to be done, rather than posting a |
| 321 // continuation task. | 319 // continuation task. |
| 322 if (!selector_.EnabledWorkQueuesEmpty()) | 320 if (!selector_.EnabledWorkQueuesEmpty()) { |
| 323 MaybePostDoWorkOnMainRunner(); | 321 MaybePostDoWorkOnMainRunner(); |
| 322 } else { |
| 323 // Tell the task runner we have no more work. |
| 324 main_task_runner_->OnNoMoreWork(); |
| 325 } |
| 324 } | 326 } |
| 325 | 327 |
| 326 bool TaskQueueManager::SelectQueueToService( | 328 bool TaskQueueManager::SelectQueueToService( |
| 327 internal::TaskQueueImpl** out_queue) { | 329 internal::TaskQueueImpl** out_queue) { |
| 328 bool should_run = selector_.SelectQueueToService(out_queue); | 330 bool should_run = selector_.SelectQueueToService(out_queue); |
| 329 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 331 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 330 disabled_by_default_tracing_category_, "TaskQueueManager", this, | 332 disabled_by_default_tracing_category_, "TaskQueueManager", this, |
| 331 AsValueWithSelectorResult(should_run, *out_queue)); | 333 AsValueWithSelectorResult(should_run, *out_queue)); |
| 332 return should_run; | 334 return should_run; |
| 333 } | 335 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 DCHECK(main_thread_checker_.CalledOnValidThread()); | 410 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 409 task_observers_.AddObserver(task_observer); | 411 task_observers_.AddObserver(task_observer); |
| 410 } | 412 } |
| 411 | 413 |
| 412 void TaskQueueManager::RemoveTaskObserver( | 414 void TaskQueueManager::RemoveTaskObserver( |
| 413 base::MessageLoop::TaskObserver* task_observer) { | 415 base::MessageLoop::TaskObserver* task_observer) { |
| 414 DCHECK(main_thread_checker_.CalledOnValidThread()); | 416 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 415 task_observers_.RemoveObserver(task_observer); | 417 task_observers_.RemoveObserver(task_observer); |
| 416 } | 418 } |
| 417 | 419 |
| 418 void TaskQueueManager::SetTimeSourceForTesting( | |
| 419 scoped_ptr<base::TickClock> time_source) { | |
| 420 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 421 time_source_ = time_source.Pass(); | |
| 422 } | |
| 423 | |
| 424 bool TaskQueueManager::GetAndClearSystemIsQuiescentBit() { | 420 bool TaskQueueManager::GetAndClearSystemIsQuiescentBit() { |
| 425 bool task_was_run = task_was_run_on_quiescence_monitored_queue_; | 421 bool task_was_run = task_was_run_on_quiescence_monitored_queue_; |
| 426 task_was_run_on_quiescence_monitored_queue_ = false; | 422 task_was_run_on_quiescence_monitored_queue_ = false; |
| 427 return !task_was_run; | 423 return !task_was_run; |
| 428 } | 424 } |
| 429 | 425 |
| 430 base::TimeTicks TaskQueueManager::Now() const { | 426 base::TickClock* TaskQueueManager::tick_clock() const { |
| 431 return time_source_->NowTicks(); | 427 return main_task_runner_.get(); |
| 432 } | 428 } |
| 433 | 429 |
| 434 int TaskQueueManager::GetNextSequenceNumber() { | 430 int TaskQueueManager::GetNextSequenceNumber() { |
| 435 return task_sequence_num_.GetNext(); | 431 return task_sequence_num_.GetNext(); |
| 436 } | 432 } |
| 437 | 433 |
| 438 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | 434 scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
| 439 TaskQueueManager::AsValueWithSelectorResult( | 435 TaskQueueManager::AsValueWithSelectorResult( |
| 440 bool should_run, | 436 bool should_run, |
| 441 internal::TaskQueueImpl* selected_queue) const { | 437 internal::TaskQueueImpl* selected_queue) const { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 460 } | 456 } |
| 461 | 457 |
| 462 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { | 458 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { |
| 463 DCHECK(main_thread_checker_.CalledOnValidThread()); | 459 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 464 // Only schedule DoWork if there's something to do. | 460 // Only schedule DoWork if there's something to do. |
| 465 if (!queue->work_queue().empty()) | 461 if (!queue->work_queue().empty()) |
| 466 MaybePostDoWorkOnMainRunner(); | 462 MaybePostDoWorkOnMainRunner(); |
| 467 } | 463 } |
| 468 | 464 |
| 469 } // namespace scheduler | 465 } // namespace scheduler |
| OLD | NEW |