| .. | ||
| test | ||
| associated_thread_id.cc | ||
| associated_thread_id.h | ||
| atomic_flag_set_unittest.cc | ||
| atomic_flag_set.cc | ||
| atomic_flag_set.h | ||
| delayed_task_handle_delegate.cc | ||
| delayed_task_handle_delegate.h | ||
| DIR_METADATA | ||
| enqueue_order_generator.cc | ||
| enqueue_order_generator.h | ||
| enqueue_order.h | ||
| fence.cc | ||
| fence.h | ||
| hierarchical_timing_wheel_unittest.cc | ||
| hierarchical_timing_wheel.cc | ||
| hierarchical_timing_wheel.h | ||
| lazily_deallocated_deque_unittest.cc | ||
| lazily_deallocated_deque.h | ||
| README.md | ||
| sequence_manager_impl_unittest.cc | ||
| sequence_manager_impl.cc | ||
| sequence_manager_impl.h | ||
| sequence_manager_perftest.cc | ||
| sequence_manager.cc | ||
| sequence_manager.h | ||
| sequenced_task_source.cc | ||
| sequenced_task_source.h | ||
| task_order_unittest.cc | ||
| task_order.cc | ||
| task_order.h | ||
| task_queue_impl.cc | ||
| task_queue_impl.h | ||
| task_queue_selector_unittest.cc | ||
| task_queue_selector.cc | ||
| task_queue_selector.h | ||
| task_queue_unittest.cc | ||
| task_queue.cc | ||
| task_queue.h | ||
| task_time_observer.h | ||
| tasks.cc | ||
| tasks.h | ||
| thread_controller_impl.cc | ||
| thread_controller_impl.h | ||
| thread_controller_power_monitor_unittest.cc | ||
| thread_controller_power_monitor.cc | ||
| thread_controller_power_monitor.h | ||
| thread_controller_with_message_pump_impl_unittest.cc | ||
| thread_controller_with_message_pump_impl.cc | ||
| thread_controller_with_message_pump_impl.h | ||
| thread_controller.cc | ||
| thread_controller.h | ||
| time_domain.cc | ||
| time_domain.h | ||
| timing_wheel_unittest.cc | ||
| timing_wheel.cc | ||
| timing_wheel.h | ||
| wake_up_queue_unittest.cc | ||
| wake_up_queue.cc | ||
| wake_up_queue.h | ||
| work_deduplicator_unittest.cc | ||
| work_deduplicator.cc | ||
| work_deduplicator.h | ||
| work_queue_sets_unittest.cc | ||
| work_queue_sets.cc | ||
| work_queue_sets.h | ||
| work_queue_unittest.cc | ||
| work_queue.cc | ||
| work_queue.h | ||
What is this
This file documents high level parts of the sequence manager.
The sequence manager provides a set of prioritized FIFO task queues, which allows funneling multiple sequences of immediate and delayed tasks on a single underlying sequence.
Work Queue and Task selection
Both immediate tasks and delayed tasks are posted to a TaskQueue via an
associated TaskRunner. TaskQueues use distinct primitive FIFO queues, called
WorkQueues, to manage immediate tasks and delayed tasks. Tasks eventually end
up in their assigned WorkQueue which is made directly visible to
SequenceManager through TaskQueueSelector.
SequenceManagerImpl::SelectNextTask() uses
TaskQueueSelector::SelectWorkQueueToService() to select the next work queue
based on various policy e.g. priority, from which 1 task is popped at a time.
Journey of a Task
Task queues have a mechanism to allow efficient cross-thread posting with the
use of 2 work queues, immediate_incoming_queue which is used when posting, and
immediate_work_queue used to pop tasks from. An immediate task posted from the
main thread is pushed on immediate_incoming_queue in
TaskQueueImpl::PostImmediateTaskImpl(). If the work queue was empty,
SequenceManager is notified and the TaskQueue is registered to do
ReloadEmptyImmediateWorkQueue() before SequenceManager selects a task, which
moves tasks from immediate_incoming_queue to immediate_work_queue in batch
for all registered TaskQueues. The tasks then follow the regular work queue
selection mechanism.
Journey of a WakeUp
A WakeUp represents a time at which a delayed task wants to run.
Each TaskQueueImpl maintains its own next wake-up as
main_thread_only().scheduled_wake_up, associated with the earliest pending
delayed task. It communicates its wake up to the WakeUpQueue via
WakeUpQueue::SetNextWakeUpForQueue(). The WakeUpQueue is responsible for
determining the single next wake up time for the thread. This is accessed from
SequenceManagerImpl and may determine the next run time if there's no
immediate work, which ultimately gets passed to the MessagePump, typically via
MessagePump::Delegate::NextWorkInfo (returned by
ThreadControllerWithMessagePumpImpl::DoWork()) or by
MessagePump::ScheduleDelayedWork() (on rare occasions where the next WakeUp is
scheduled on the main thread from outside a DoWork()). When a delayed run time
associated with a wake-up is reached, WakeUpQueue is notified through
WakeUpQueue::MoveReadyDelayedTasksToWorkQueues() and in turn notifies all
TaskQueues whose wake-up can be resolved. This lets each TaskQueues process
ripe delayed tasks.
Journey of a delayed Task
A delayed Task posted cross-thread generates an immediate Task to run
TaskQueueImpl::ScheduleDelayedWorkTask() which eventually calls
TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread(), so that it can be
enqueued on the main thread. A delayed Task posted from the main thread skips
this step and calls
TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread() directly. The Task
is then pushed on main_thread_only().delayed_incoming_queue and possibly
updates the next task queue wake-up. Once the delayed run time is reached,
possibly because the wake-up is resolved, the delayed task is moved to
main_thread_only().delayed_work_queue and follows the regular work queue
selection mechanism.
TimeDomain and TickClock
SequenceManager and related classes use a common TickClock that can be
injected by specifying a TimeDomain. A TimeDomain is a specialisation of
TickClock that gets notified when the MessagePump is about to go idle via
TimeDomain::MaybeFastForwardToWakeUp(), and can use the signal to fast forward
in time. This is used in TaskEnvironment to support MOCK_TIME, and in
devtools to support virtual time.