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 |