xref: /aosp_15_r20/external/pigweed/pw_async2/guides.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-quickstart-guides:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker===================
4*61c4878aSAndroid Build Coastguard WorkerQuickstart & guides
5*61c4878aSAndroid Build Coastguard Worker===================
6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module-subpage::
7*61c4878aSAndroid Build Coastguard Worker   :name: pw_async2
8*61c4878aSAndroid Build Coastguard Worker
9*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides:
10*61c4878aSAndroid Build Coastguard Worker
11*61c4878aSAndroid Build Coastguard Worker------
12*61c4878aSAndroid Build Coastguard WorkerGuides
13*61c4878aSAndroid Build Coastguard Worker------
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard WorkerImplementing tasks
16*61c4878aSAndroid Build Coastguard Worker==================
17*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::async2::Task` instances complete one or more asynchronous
18*61c4878aSAndroid Build Coastguard Workeroperations. They are the top-level "thread" primitives of ``pw_async2``.
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard WorkerYou can use one of the concrete subclasses of ``Task`` that Pigweed provides:
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker* :cpp:class:`pw::async2::CoroOrElseTask`: Delegates to a provided
23*61c4878aSAndroid Build Coastguard Worker  coroutine and executes an ``or_else`` handler function on failure.
24*61c4878aSAndroid Build Coastguard Worker* :cpp:class:`pw::async2::PendFuncTask`: Delegates to a provided
25*61c4878aSAndroid Build Coastguard Worker  function.
26*61c4878aSAndroid Build Coastguard Worker* :cpp:class:`pw::async2::PendableAsTask`: Delegates to a type
27*61c4878aSAndroid Build Coastguard Worker  with a :cpp:func:`pw::async2::Pend` method.
28*61c4878aSAndroid Build Coastguard Worker* :cpp:func:`pw::async2::AllocateTask`: Creates a concrete subclass of
29*61c4878aSAndroid Build Coastguard Worker  ``Task``, just like ``PendableAsTask``, but the created task is
30*61c4878aSAndroid Build Coastguard Worker  dynamically allocated and frees the associated memory upon
31*61c4878aSAndroid Build Coastguard Worker  completion.
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard WorkerOr you can subclass ``Task`` yourself. See :cpp:class:`pw::async2::Task`
34*61c4878aSAndroid Build Coastguard Workerfor more guidance on subclassing.
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-tasks:
37*61c4878aSAndroid Build Coastguard Worker
38*61c4878aSAndroid Build Coastguard WorkerHow a dispatcher manages tasks
39*61c4878aSAndroid Build Coastguard Worker==============================
40*61c4878aSAndroid Build Coastguard WorkerThe purpose of a :cpp:class:`pw::async2::Dispatcher` is to keep track of a set
41*61c4878aSAndroid Build Coastguard Workerof :cpp:class:`pw::async2::Task` objects and run them to completion. The
42*61c4878aSAndroid Build Coastguard Workerdispatcher is essentially a scheduler for cooperatively-scheduled
43*61c4878aSAndroid Build Coastguard Worker(non-preemptive) threads (tasks).
44*61c4878aSAndroid Build Coastguard Worker
45*61c4878aSAndroid Build Coastguard WorkerWhile a dispatcher is running, it waits for one or more tasks to waken and then
46*61c4878aSAndroid Build Coastguard Workeradvances each task by invoking its :cpp:func:`pw::async2::Task::DoPend` method.
47*61c4878aSAndroid Build Coastguard WorkerThe ``DoPend`` method is typically implemented manually by users, though it is
48*61c4878aSAndroid Build Coastguard Workerautomatically provided by coroutines.
49*61c4878aSAndroid Build Coastguard Worker
50*61c4878aSAndroid Build Coastguard WorkerIf the task is able to complete, ``DoPend`` will return ``Ready``, in which case
51*61c4878aSAndroid Build Coastguard Workerthe task is then deregistered from the dispatcher.
52*61c4878aSAndroid Build Coastguard Worker
53*61c4878aSAndroid Build Coastguard WorkerIf the task is unable to complete, ``DoPend`` must return ``Pending`` and arrange
54*61c4878aSAndroid Build Coastguard Workerfor the task to be woken up when it is able to make progress again. Once the
55*61c4878aSAndroid Build Coastguard Workertask is rewoken, the task is re-added to the ``Dispatcher`` queue. The
56*61c4878aSAndroid Build Coastguard Workerdispatcher will then invoke ``DoPend`` once more, continuing the cycle until
57*61c4878aSAndroid Build Coastguard Worker``DoPend`` returns ``Ready`` and the task is completed.
58*61c4878aSAndroid Build Coastguard Worker
59*61c4878aSAndroid Build Coastguard WorkerThe following sequence diagram summarizes the basic workflow:
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker.. mermaid::
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard Worker   sequenceDiagram
64*61c4878aSAndroid Build Coastguard Worker       participant e as External Event e.g. Interrupt
65*61c4878aSAndroid Build Coastguard Worker       participant d as Dispatcher
66*61c4878aSAndroid Build Coastguard Worker       participant t as Task
67*61c4878aSAndroid Build Coastguard Worker       e->>t: Init Task
68*61c4878aSAndroid Build Coastguard Worker       e->>d: Register task via Dispatcher::Post(Task)
69*61c4878aSAndroid Build Coastguard Worker       d->>d: Add task to queue
70*61c4878aSAndroid Build Coastguard Worker       d->>t: Run task via Task::DoPend()
71*61c4878aSAndroid Build Coastguard Worker       t->>t: Task is waiting for data and can't yet complete
72*61c4878aSAndroid Build Coastguard Worker       t->>e: Arrange for rewake via PW_ASYNC_STORE_WAKER
73*61c4878aSAndroid Build Coastguard Worker       t->>d: Indicate that task is not complete via Pending()
74*61c4878aSAndroid Build Coastguard Worker       d->>d: Remove task from queue
75*61c4878aSAndroid Build Coastguard Worker       d->>d: Go to sleep because task queue is empty
76*61c4878aSAndroid Build Coastguard Worker       e->>e: The data that the task needs has arrived
77*61c4878aSAndroid Build Coastguard Worker       e->>d: Rewake via Waker::Wake()
78*61c4878aSAndroid Build Coastguard Worker       d->>d: Re-add task to queue
79*61c4878aSAndroid Build Coastguard Worker       d->>t: Run task via Task::DoPend()
80*61c4878aSAndroid Build Coastguard Worker       t->>t: Task runs to completion
81*61c4878aSAndroid Build Coastguard Worker       t->>d: Indicate that task is complete via Ready()
82*61c4878aSAndroid Build Coastguard Worker       d->>d: Deregister the task
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-pendables:
85*61c4878aSAndroid Build Coastguard Worker
86*61c4878aSAndroid Build Coastguard WorkerImplementing invariants for pendable functions
87*61c4878aSAndroid Build Coastguard Worker==============================================
88*61c4878aSAndroid Build Coastguard Worker.. _invariants: https://stackoverflow.com/a/112088
89*61c4878aSAndroid Build Coastguard Worker
90*61c4878aSAndroid Build Coastguard WorkerAny ``Pend``-like function or method similar to
91*61c4878aSAndroid Build Coastguard Worker:cpp:func:`pw::async2::Task::DoPend` that can pause when it's not able
92*61c4878aSAndroid Build Coastguard Workerto make progress on its task is known as a **pendable function**. When
93*61c4878aSAndroid Build Coastguard Workerimplementing a pendable function, make sure that you always uphold the
94*61c4878aSAndroid Build Coastguard Workerfollowing `invariants`_:
95*61c4878aSAndroid Build Coastguard Worker
96*61c4878aSAndroid Build Coastguard Worker* :ref:`module-pw_async2-guides-pendables-incomplete`
97*61c4878aSAndroid Build Coastguard Worker* :ref:`module-pw_async2-guides-pendables-complete`
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker.. note:: Exactly which APIs are considered pendable?
100*61c4878aSAndroid Build Coastguard Worker
101*61c4878aSAndroid Build Coastguard Worker   If it has the signature ``(Context&, ...) -> Poll<T>``,
102*61c4878aSAndroid Build Coastguard Worker   then it's a pendable function.
103*61c4878aSAndroid Build Coastguard Worker
104*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-pendables-incomplete:
105*61c4878aSAndroid Build Coastguard Worker
106*61c4878aSAndroid Build Coastguard WorkerArranging future completion of incomplete tasks
107*61c4878aSAndroid Build Coastguard Worker-----------------------------------------------
108*61c4878aSAndroid Build Coastguard WorkerWhen your pendable function can't yet complete:
109*61c4878aSAndroid Build Coastguard Worker
110*61c4878aSAndroid Build Coastguard Worker#. Do one of the following to make sure the task rewakes when it's ready to
111*61c4878aSAndroid Build Coastguard Worker   make more progress:
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker   * Delegate waking to a subtask. Arrange for that subtask's
114*61c4878aSAndroid Build Coastguard Worker     pendable function to wake this task when appropriate.
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker   * Arrange an external wakeup. Use :c:macro:`PW_ASYNC_STORE_WAKER`
117*61c4878aSAndroid Build Coastguard Worker     to store the task's waker somewhere, and then call
118*61c4878aSAndroid Build Coastguard Worker     :cpp:func:`pw::async2::Waker::Wake` from an interrupt or another thread
119*61c4878aSAndroid Build Coastguard Worker     once the event that the task is waiting for has completed.
120*61c4878aSAndroid Build Coastguard Worker
121*61c4878aSAndroid Build Coastguard Worker   * Re-enqueue the task with :cpp:func:`pw::async2::Context::ReEnqueue`.
122*61c4878aSAndroid Build Coastguard Worker     This is a rare case. Usually, you should just create an immediately
123*61c4878aSAndroid Build Coastguard Worker     invoked ``Waker``.
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard Worker#. Make sure to return :cpp:type:`pw::async2::Pending` to signal that the task
126*61c4878aSAndroid Build Coastguard Worker   is incomplete.
127*61c4878aSAndroid Build Coastguard Worker
128*61c4878aSAndroid Build Coastguard WorkerIn other words, whenever your pendable function returns
129*61c4878aSAndroid Build Coastguard Worker:cpp:type:`pw::async2::Pending`, you must guarantee that
130*61c4878aSAndroid Build Coastguard Worker:cpp:func:`pw::async2::Context::Wake` is called once in the future.
131*61c4878aSAndroid Build Coastguard Worker
132*61c4878aSAndroid Build Coastguard WorkerFor example, one implementation of a delayed task might arrange for its ``Waker``
133*61c4878aSAndroid Build Coastguard Workerto be woken by a timer once some time has passed. Another case might be a
134*61c4878aSAndroid Build Coastguard Workermessaging library which calls ``Wake()`` on the receiving task once a sender has
135*61c4878aSAndroid Build Coastguard Workerplaced a message in a queue.
136*61c4878aSAndroid Build Coastguard Worker
137*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-pendables-complete:
138*61c4878aSAndroid Build Coastguard Worker
139*61c4878aSAndroid Build Coastguard WorkerCleaning up complete tasks
140*61c4878aSAndroid Build Coastguard Worker--------------------------
141*61c4878aSAndroid Build Coastguard WorkerWhen your pendable function has completed, make sure to return
142*61c4878aSAndroid Build Coastguard Worker:cpp:type:`pw::async2::Ready` to signal that the task is complete.
143*61c4878aSAndroid Build Coastguard Worker
144*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-passing-data:
145*61c4878aSAndroid Build Coastguard Worker
146*61c4878aSAndroid Build Coastguard WorkerPassing data between tasks
147*61c4878aSAndroid Build Coastguard Worker==========================
148*61c4878aSAndroid Build Coastguard WorkerAstute readers will have noticed that the ``Wake`` method does not take any
149*61c4878aSAndroid Build Coastguard Workerarguments, and ``DoPoll`` does not provide the task being polled with any
150*61c4878aSAndroid Build Coastguard Workervalues!
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard WorkerUnlike callback-based interfaces, tasks (and the libraries they use)
153*61c4878aSAndroid Build Coastguard Workerare responsible for storage of the inputs and outputs of events. A common
154*61c4878aSAndroid Build Coastguard Workertechnique is for a task implementation to provide storage for outputs of an
155*61c4878aSAndroid Build Coastguard Workerevent. Then, upon completion of the event, the outputs will be stored in the
156*61c4878aSAndroid Build Coastguard Workertask before it is woken. The task will then be invoked again by the
157*61c4878aSAndroid Build Coastguard Workerdispatcher and can then operate on the resulting values.
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard WorkerThis common pattern is implemented by the
160*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::async2::OnceSender` and
161*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::async2::OnceReceiver` types (and their ``...Ref`` counterparts).
162*61c4878aSAndroid Build Coastguard WorkerThese interfaces allow a task to asynchronously wait for a value:
163*61c4878aSAndroid Build Coastguard Worker
164*61c4878aSAndroid Build Coastguard Worker.. tab-set::
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: Manual ``Task`` State Machine
167*61c4878aSAndroid Build Coastguard Worker
168*61c4878aSAndroid Build Coastguard Worker      .. literalinclude:: examples/once_send_recv.cc
169*61c4878aSAndroid Build Coastguard Worker         :language: cpp
170*61c4878aSAndroid Build Coastguard Worker         :linenos:
171*61c4878aSAndroid Build Coastguard Worker         :start-after: [pw_async2-examples-once-send-recv-manual]
172*61c4878aSAndroid Build Coastguard Worker         :end-before: [pw_async2-examples-once-send-recv-manual]
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: Coroutine Function
175*61c4878aSAndroid Build Coastguard Worker
176*61c4878aSAndroid Build Coastguard Worker      .. literalinclude:: examples/once_send_recv.cc
177*61c4878aSAndroid Build Coastguard Worker         :language: cpp
178*61c4878aSAndroid Build Coastguard Worker         :linenos:
179*61c4878aSAndroid Build Coastguard Worker         :start-after: [pw_async2-examples-once-send-recv-coro]
180*61c4878aSAndroid Build Coastguard Worker         :end-before: [pw_async2-examples-once-send-recv-coro]
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard WorkerMore primitives (such as ``MultiSender`` and ``MultiReceiver``) are in-progress.
183*61c4878aSAndroid Build Coastguard WorkerUsers who find that they need other async primitives are encouraged to
184*61c4878aSAndroid Build Coastguard Workercontribute them upstream to ``pw::async2``!
185*61c4878aSAndroid Build Coastguard Worker
186*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-coroutines:
187*61c4878aSAndroid Build Coastguard Worker
188*61c4878aSAndroid Build Coastguard WorkerCoroutines
189*61c4878aSAndroid Build Coastguard Worker==========
190*61c4878aSAndroid Build Coastguard WorkerC++20 users can define tasks using coroutines!
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: examples/basic.cc
193*61c4878aSAndroid Build Coastguard Worker   :language: cpp
194*61c4878aSAndroid Build Coastguard Worker   :linenos:
195*61c4878aSAndroid Build Coastguard Worker   :start-after: [pw_async2-examples-basic-coro]
196*61c4878aSAndroid Build Coastguard Worker   :end-before: [pw_async2-examples-basic-coro]
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard WorkerAny value with a ``Poll<T> Pend(Context&)`` method can be passed to
199*61c4878aSAndroid Build Coastguard Worker``co_await``, which will return with a ``T`` when the result is ready.
200*61c4878aSAndroid Build Coastguard Worker
201*61c4878aSAndroid Build Coastguard WorkerTo return from a coroutine, ``co_return <expression>`` must be used instead of
202*61c4878aSAndroid Build Coastguard Workerthe usual ``return <expression>`` syntax. Because of this, the
203*61c4878aSAndroid Build Coastguard Worker:c:macro:`PW_TRY` and :c:macro:`PW_TRY_ASSIGN` macros are not usable within
204*61c4878aSAndroid Build Coastguard Workercoroutines. :c:macro:`PW_CO_TRY` and :c:macro:`PW_CO_TRY_ASSIGN` should be
205*61c4878aSAndroid Build Coastguard Workerused instead.
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard WorkerFor a more detailed explanation of Pigweed's coroutine support, see
208*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::async2::Coro`.
209*61c4878aSAndroid Build Coastguard Worker
210*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-timing:
211*61c4878aSAndroid Build Coastguard Worker
212*61c4878aSAndroid Build Coastguard WorkerTiming
213*61c4878aSAndroid Build Coastguard Worker======
214*61c4878aSAndroid Build Coastguard WorkerWhen using ``pw::async2``, timing functionality should be injected
215*61c4878aSAndroid Build Coastguard Workerby accepting a :cpp:class:`pw::async2::TimeProvider` (most commonly
216*61c4878aSAndroid Build Coastguard Worker``TimeProvider<SystemClock>`` when using the system's built-in ``time_point``
217*61c4878aSAndroid Build Coastguard Workerand ``duration`` types).
218*61c4878aSAndroid Build Coastguard Worker
219*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::async2::TimeProvider` allows for easily waiting
220*61c4878aSAndroid Build Coastguard Workerfor a timeout or deadline using the
221*61c4878aSAndroid Build Coastguard Worker:cpp:func:`pw::async2::TimePoint::WaitFor` and
222*61c4878aSAndroid Build Coastguard Worker:cpp:func:`pw::async2::TimePoint::WaitUntil` methods.
223*61c4878aSAndroid Build Coastguard Worker
224*61c4878aSAndroid Build Coastguard WorkerAdditionally, code which uses :cpp:class:`pw::async2::TimeProvider` for timing
225*61c4878aSAndroid Build Coastguard Workercan be tested with simulated time using
226*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::async2::SimulatedTimeProvider`. Doing so helps avoid
227*61c4878aSAndroid Build Coastguard Workertiming-dependent test flakes and helps ensure that tests are fast since they
228*61c4878aSAndroid Build Coastguard Workerdon't need to wait for real-world time to elapse.
229*61c4878aSAndroid Build Coastguard Worker
230*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async2-guides-faqs:
231*61c4878aSAndroid Build Coastguard Worker
232*61c4878aSAndroid Build Coastguard Worker---------------------------------
233*61c4878aSAndroid Build Coastguard WorkerFrequently asked questions (FAQs)
234*61c4878aSAndroid Build Coastguard Worker---------------------------------
235