xref: /aosp_15_r20/external/pigweed/pw_async/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_async:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker========
4*61c4878aSAndroid Build Coastguard Workerpw_async
5*61c4878aSAndroid Build Coastguard Worker========
6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module::
7*61c4878aSAndroid Build Coastguard Worker   :name: pw_async
8*61c4878aSAndroid Build Coastguard Worker
9*61c4878aSAndroid Build Coastguard Worker--------
10*61c4878aSAndroid Build Coastguard WorkerOverview
11*61c4878aSAndroid Build Coastguard Worker--------
12*61c4878aSAndroid Build Coastguard WorkerPigweed's async module provides portable APIs and utilities for writing
13*61c4878aSAndroid Build Coastguard Workerasynchronous code. Currently, it provides:
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker- Message loop APIs
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker.. attention::
18*61c4878aSAndroid Build Coastguard Worker  This module is still under construction. The API is not yet stable.
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard Worker----------
21*61c4878aSAndroid Build Coastguard WorkerDispatcher
22*61c4878aSAndroid Build Coastguard Worker----------
23*61c4878aSAndroid Build Coastguard WorkerDispatcher is an API for a message loop that schedules and executes Tasks. See
24*61c4878aSAndroid Build Coastguard Worker:bdg-ref-primary-line:`module-pw_async_basic` for an example implementation.
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard WorkerDispatcher is a pure virtual interface that is implemented by backends and
27*61c4878aSAndroid Build Coastguard WorkerFakeDispatcher. A virtual interface is used instead of a facade to allow
28*61c4878aSAndroid Build Coastguard Workersubstituting a FakeDispatcher for a Dispatcher backend in tests.
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard WorkerDispatcher API
31*61c4878aSAndroid Build Coastguard Worker==============
32*61c4878aSAndroid Build Coastguard Worker.. doxygenclass:: pw::async::Dispatcher
33*61c4878aSAndroid Build Coastguard Worker   :members:
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard WorkerTask API
37*61c4878aSAndroid Build Coastguard Worker==============
38*61c4878aSAndroid Build Coastguard Worker.. doxygenstruct:: pw::async::Context
39*61c4878aSAndroid Build Coastguard Worker   :members:
40*61c4878aSAndroid Build Coastguard Worker
41*61c4878aSAndroid Build Coastguard Worker.. doxygentypedef:: pw::async::TaskFunction
42*61c4878aSAndroid Build Coastguard Worker
43*61c4878aSAndroid Build Coastguard Worker.. doxygenclass:: pw::async::Task
44*61c4878aSAndroid Build Coastguard Worker   :members:
45*61c4878aSAndroid Build Coastguard Worker
46*61c4878aSAndroid Build Coastguard WorkerFacade API
47*61c4878aSAndroid Build Coastguard Worker==========
48*61c4878aSAndroid Build Coastguard Worker
49*61c4878aSAndroid Build Coastguard WorkerTask
50*61c4878aSAndroid Build Coastguard Worker----
51*61c4878aSAndroid Build Coastguard WorkerThe ``Task`` type represents a work item that can be submitted to and executed
52*61c4878aSAndroid Build Coastguard Workerby a ``Dispatcher``.
53*61c4878aSAndroid Build Coastguard Worker
54*61c4878aSAndroid Build Coastguard WorkerTo run work on a ``Dispatcher`` event loop, a ``Task`` can be constructed from
55*61c4878aSAndroid Build Coastguard Workera function or lambda (see ``pw::async::TaskFunction``) and submitted to run
56*61c4878aSAndroid Build Coastguard Workerusing the ``pw::async::Dispatcher::Post`` method (and its siblings, ``PostAt``
57*61c4878aSAndroid Build Coastguard Workeretc.).
58*61c4878aSAndroid Build Coastguard Worker
59*61c4878aSAndroid Build Coastguard WorkerThe ``Task`` facade enables backends to provide custom storage containers for
60*61c4878aSAndroid Build Coastguard Worker``Task`` s, as well as to keep per- ``Task`` data alongside the ``TaskFunction``
61*61c4878aSAndroid Build Coastguard Worker(such as ``next`` pointers for intrusive linked-lists of ``Task``).
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard WorkerThe active Task backend is configured with the GN variable
64*61c4878aSAndroid Build Coastguard Worker``pw_async_TASK_BACKEND``. The specified target must define a class
65*61c4878aSAndroid Build Coastguard Worker``pw::async::backend::NativeTask`` in the header ``pw_async_backend/task.h``
66*61c4878aSAndroid Build Coastguard Workerthat meets the interface requirements in ``public/pw_async/task.h``. Task will
67*61c4878aSAndroid Build Coastguard Workerthen trivially wrap ``NativeTask``.
68*61c4878aSAndroid Build Coastguard Worker
69*61c4878aSAndroid Build Coastguard WorkerThe bazel build provides the ``pw_async_task_backend`` label flag to configure
70*61c4878aSAndroid Build Coastguard Workerthe active Task backend.
71*61c4878aSAndroid Build Coastguard Worker
72*61c4878aSAndroid Build Coastguard WorkerFakeDispatcher
73*61c4878aSAndroid Build Coastguard Worker--------------
74*61c4878aSAndroid Build Coastguard WorkerThe FakeDispatcher facade is a utility for simulating a real Dispatcher
75*61c4878aSAndroid Build Coastguard Workerin tests. FakeDispatcher simulates time to allow for reliable, fast testing of
76*61c4878aSAndroid Build Coastguard Workercode that uses Dispatcher. FakeDispatcher is a facade instead of a concrete
77*61c4878aSAndroid Build Coastguard Workerimplementation because it depends on Task state for processing tasks, which
78*61c4878aSAndroid Build Coastguard Workervaries across Task backends.
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard WorkerThe active FakeDispatcher backend is configured with the GN variable
81*61c4878aSAndroid Build Coastguard Worker``pw_async_FAKE_DISPATCHER_BACKEND``. The specified target must define a class
82*61c4878aSAndroid Build Coastguard Worker``pw::async::test::backend::NativeFakeDispatcher`` in the header
83*61c4878aSAndroid Build Coastguard Worker``pw_async_backend/fake_dispatcher.h`` that meets the interface requirements in
84*61c4878aSAndroid Build Coastguard Worker``public/pw_async/task.h``. FakeDispatcher will then trivially wrap
85*61c4878aSAndroid Build Coastguard Worker``NativeFakeDispatcher``.
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard WorkerThe bazel build provides the ``pw_async_fake_dispatcher_backend`` label flag to
88*61c4878aSAndroid Build Coastguard Workerconfigure the FakeDispatcher backend.
89*61c4878aSAndroid Build Coastguard Worker
90*61c4878aSAndroid Build Coastguard WorkerTesting FakeDispatcher
91*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^
92*61c4878aSAndroid Build Coastguard WorkerThe GN template ``fake_dispatcher_tests`` in ``fake_dispatcher_tests.gni``
93*61c4878aSAndroid Build Coastguard Workercreates a test target that tests a FakeDispatcher backend. This enables
94*61c4878aSAndroid Build Coastguard Workerone test suite to be shared across FakeDispatcher backends and ensures
95*61c4878aSAndroid Build Coastguard Workerconformance.
96*61c4878aSAndroid Build Coastguard Worker
97*61c4878aSAndroid Build Coastguard WorkerFunctionDispatcher
98*61c4878aSAndroid Build Coastguard Worker------------------
99*61c4878aSAndroid Build Coastguard Worker.. doxygenclass:: pw::async::FunctionDispatcher
100*61c4878aSAndroid Build Coastguard Worker   :members:
101*61c4878aSAndroid Build Coastguard Worker
102*61c4878aSAndroid Build Coastguard WorkerHeapDispatcher
103*61c4878aSAndroid Build Coastguard Worker--------------
104*61c4878aSAndroid Build Coastguard Worker.. doxygenclass:: pw::async::HeapDispatcher
105*61c4878aSAndroid Build Coastguard Worker   :members:
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard WorkerDesign
108*61c4878aSAndroid Build Coastguard Worker======
109*61c4878aSAndroid Build Coastguard Worker
110*61c4878aSAndroid Build Coastguard WorkerTask Ownership
111*61c4878aSAndroid Build Coastguard Worker--------------
112*61c4878aSAndroid Build Coastguard WorkerTasks are owned by clients rather than the Dispatcher. This avoids either
113*61c4878aSAndroid Build Coastguard Workermemory allocation or queue size limits in Dispatcher implementations. However,
114*61c4878aSAndroid Build Coastguard Workercare must be taken that clients do not destroy Tasks before they have been
115*61c4878aSAndroid Build Coastguard Workerexecuted or canceled.
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard WorkerGetting Started
118*61c4878aSAndroid Build Coastguard Worker===============
119*61c4878aSAndroid Build Coastguard WorkerFirst, configure the Task backend for the Dispatcher backend you will be using:
120*61c4878aSAndroid Build Coastguard Worker
121*61c4878aSAndroid Build Coastguard Worker.. code-block::
122*61c4878aSAndroid Build Coastguard Worker
123*61c4878aSAndroid Build Coastguard Worker   pw_async_TASK_BACKEND = "$dir_pw_async_basic:task"
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard Worker
126*61c4878aSAndroid Build Coastguard WorkerNext, create an executable target that depends on the Dispatcher backend you
127*61c4878aSAndroid Build Coastguard Workerwant to use:
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker.. code-block::
130*61c4878aSAndroid Build Coastguard Worker
131*61c4878aSAndroid Build Coastguard Worker   pw_executable("hello_world") {
132*61c4878aSAndroid Build Coastguard Worker     sources = [ "main.cc" ]
133*61c4878aSAndroid Build Coastguard Worker     deps = [ "$dir_pw_async_basic:dispatcher" ]
134*61c4878aSAndroid Build Coastguard Worker   }
135*61c4878aSAndroid Build Coastguard Worker
136*61c4878aSAndroid Build Coastguard WorkerNext, instantiate the Dispatcher and post a task:
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
139*61c4878aSAndroid Build Coastguard Worker
140*61c4878aSAndroid Build Coastguard Worker   #include "pw_async_basic/dispatcher.h"
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker   int main() {
143*61c4878aSAndroid Build Coastguard Worker     BasicDispatcher dispatcher;
144*61c4878aSAndroid Build Coastguard Worker
145*61c4878aSAndroid Build Coastguard Worker     // Spawn a thread for the dispatcher to run on.
146*61c4878aSAndroid Build Coastguard Worker     Thread work_thread(thread::stl::Options(), dispatcher);
147*61c4878aSAndroid Build Coastguard Worker
148*61c4878aSAndroid Build Coastguard Worker     Task task([](pw::async::Context& ctx){
149*61c4878aSAndroid Build Coastguard Worker       printf("hello world\n");
150*61c4878aSAndroid Build Coastguard Worker       ctx.dispatcher->RequestStop();
151*61c4878aSAndroid Build Coastguard Worker     });
152*61c4878aSAndroid Build Coastguard Worker
153*61c4878aSAndroid Build Coastguard Worker     // Execute `task` in 5 seconds.
154*61c4878aSAndroid Build Coastguard Worker     dispatcher.PostAfter(task, 5s);
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker     // Blocks until `task` runs.
157*61c4878aSAndroid Build Coastguard Worker     work_thread.join();
158*61c4878aSAndroid Build Coastguard Worker     return 0;
159*61c4878aSAndroid Build Coastguard Worker   }
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard WorkerThe above example runs the dispatcher on a new thread, but it can also run on
162*61c4878aSAndroid Build Coastguard Workerthe current/main thread:
163*61c4878aSAndroid Build Coastguard Worker
164*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker   #include "pw_async_basic/dispatcher.h"
167*61c4878aSAndroid Build Coastguard Worker
168*61c4878aSAndroid Build Coastguard Worker   int main() {
169*61c4878aSAndroid Build Coastguard Worker     BasicDispatcher dispatcher;
170*61c4878aSAndroid Build Coastguard Worker
171*61c4878aSAndroid Build Coastguard Worker     Task task([](pw::async::Context& ctx){
172*61c4878aSAndroid Build Coastguard Worker       printf("hello world\n");
173*61c4878aSAndroid Build Coastguard Worker     });
174*61c4878aSAndroid Build Coastguard Worker
175*61c4878aSAndroid Build Coastguard Worker     // Execute `task` in 5 seconds.
176*61c4878aSAndroid Build Coastguard Worker     dispatcher.PostAfter(task, 5s);
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard Worker     dispatcher.Run();
179*61c4878aSAndroid Build Coastguard Worker     return 0;
180*61c4878aSAndroid Build Coastguard Worker   }
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard WorkerFake Dispatcher
183*61c4878aSAndroid Build Coastguard Worker===============
184*61c4878aSAndroid Build Coastguard WorkerTo test async code, FakeDispatcher should be dependency injected in place of
185*61c4878aSAndroid Build Coastguard WorkerDispatcher. Then, time should be driven in unit tests using the ``Run*()``
186*61c4878aSAndroid Build Coastguard Workermethods. For convenience, you can use the test fixture
187*61c4878aSAndroid Build Coastguard WorkerFakeDispatcherFixture.
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard Worker.. doxygenclass:: pw::async::test::FakeDispatcherFixture
190*61c4878aSAndroid Build Coastguard Worker   :members:
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard Worker.. attention::
193*61c4878aSAndroid Build Coastguard Worker
194*61c4878aSAndroid Build Coastguard Worker   ``FakeDispatcher::now()`` will return the simulated time.
195*61c4878aSAndroid Build Coastguard Worker   ``Dispatcher::now()`` should therefore be used to get the current time in
196*61c4878aSAndroid Build Coastguard Worker   async code instead of other sources of time to ensure consistent time values
197*61c4878aSAndroid Build Coastguard Worker   and reliable tests.
198*61c4878aSAndroid Build Coastguard Worker
199*61c4878aSAndroid Build Coastguard Worker-------
200*61c4878aSAndroid Build Coastguard WorkerRoadmap
201*61c4878aSAndroid Build Coastguard Worker-------
202*61c4878aSAndroid Build Coastguard Worker- Stabilize Task cancellation API
203*61c4878aSAndroid Build Coastguard Worker- Utility for dynamically allocated Tasks
204*61c4878aSAndroid Build Coastguard Worker- CMake support
205*61c4878aSAndroid Build Coastguard Worker- Support for C++20 coroutines
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard Worker.. toctree::
208*61c4878aSAndroid Build Coastguard Worker   :hidden:
209*61c4878aSAndroid Build Coastguard Worker   :maxdepth: 1
210*61c4878aSAndroid Build Coastguard Worker
211*61c4878aSAndroid Build Coastguard Worker   Backends <backends>
212