[tasks]: Create simple sequence_manager/ README.md
To document components that involve several classes. Change-Id: Idbb4bc2beb3ecfe8616f3d795d22bb044ea95c1e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3261898 Reviewed-by: Gabriel Charette <gab@chromium.org> Reviewed-by: Francois Pierre Doray <fdoray@chromium.org> Reviewed-by: Alexander Timin <altimin@chromium.org> Reviewed-by: Sami Kyöstilä <skyostil@chromium.org> Commit-Queue: Etienne Pierre-Doray <etiennep@chromium.org> Cr-Commit-Position: refs/heads/main@{#956499}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
4cb8ce233b
commit
f03f9a3c09
68
base/task/sequence_manager/README.md
Normal file
68
base/task/sequence_manager/README.md
Normal file
@ -0,0 +1,68 @@
|
||||
# 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`. `TaskQueue`s use distinct primitive FIFO queues, called
|
||||
`WorkQueue`s, 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 `TaskQueue`s. 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
|
||||
`TaskQueue`s whose wake-up can be resolved. This lets each `TaskQueue`s 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.
|
Reference in New Issue
Block a user