1# libasync and friends
2
3This set of libraries defines a C and C++ language interface for initiating
4asynchronous operations and dispatching their results to callback functions.
5
6The purpose of these libraries is to decouple clients which want to perform
7asynchronous operations from the message loop implementations which dispatch
8the results of those operations.  This makes it an important building block
9for other abstractions such as the FIDL bindings.
10
11## Libraries
12
13The async package consists of three libraries:
14
15- `libasync.a` provides the C client API which includes all of the function
16and structures declared in the following headers:
17    - [async/dispatcher.h](include/lib/async/dispatcher.h)
18    - [async/receiver.h](include/lib/async/receiver.h)
19    - [async/task.h](include/lib/async/task.h)
20    - [async/time.h](include/lib/async/time.h)
21    - [async/trap.h](include/lib/async/trap.h)
22    - [async/wait.h](include/lib/async/wait.h)
23
24- `libasync-cpp.a` provides C++ wrappers:
25    - [async/cpp/receiver.h](include/lib/async/cpp/receiver.h)
26    - [async/cpp/task.h](include/lib/async/cpp/task.h)
27    - [async/cpp/time.h](include/lib/async/cpp/time.h)
28    - [async/cpp/trap.h](include/lib/async/cpp/trap.h)
29    - [async/cpp/wait.h](include/lib/async/cpp/wait.h)
30
31- `libasync-default.so` provides functions for getting or setting a thread-local
32default asynchronous dispatcher as declared in [async/default.h](include/lib/async/default.h).
33
34See also [libasync-loop.a](../async-loop/README.md) which provides a general-purpose
35implementation of `async_dispatcher_t`.
36
37## Using the asynchronous dispatcher
38
39### Waiting for signals
40
41To asynchronously wait for signals, the client prepares an `async_wait_t`
42structure then calls `async_begin_wait()` to register it with the dispatcher.
43When the wait completes, the dispatcher invokes the handler.
44
45The client can register handlers from any thread but dispatch will occur
46on a thread of the dispatcher's choosing depending on its implementation.
47
48The client is responsible for ensuring that the wait structure remains in
49memory until the wait's handler runs or the wait is successfully canceled using
50`async_cancel_wait()`.
51
52See [async/wait.h](include/lib/async/wait.h) for details.
53
54```c
55#include <lib/async/wait.h>     // for async_begin_wait()
56#include <lib/async/default.h>  // for async_get_default_dispatcher()
57
58void handler(async_dispatcher_t* async, async_wait_t* wait,
59             zx_status_t status, const zx_packet_signal_t* signal) {
60    printf("signal received: status=%d, observed=%d", status, signal ? signal->observed : 0);
61    free(wait);
62}
63
64zx_status_t await(zx_handle_t object, zx_signals_t trigger, void* data) {
65    async_dispatcher_t* async = async_get_default_dispatcher();
66    async_wait_t* wait = calloc(1, sizeof(async_wait_t));
67    wait->handler = handler;
68    wait->object = object;
69    wait->trigger = trigger;
70    return async_begin_wait(async, wait);
71}
72```
73
74### Waiting for exceptions
75
76To asynchronously wait for exceptions, the client prepares an
77`async_exception_t` structure then calls `async_bind_exception_port()`
78to register it with the dispatcher. When an exception happens, the dispatcher
79invokes the handler.
80
81The client can register handlers from any thread but dispatch will occur
82on a thread of the dispatcher's choosing depending on its implementation.
83
84The client is responsible for ensuring that the exception structure remains in
85memory until the port is successfully unbound using
86`async_unbind_exception_port()`.
87
88See [async/exception.h](include/lib/async/exception.h) for details.
89
90```c
91#include <lib/async/wait.h>     // for async_begin_wait()
92#include <lib/async/default.h>  // for async_get_default_dispatcher()
93
94void handler(async_dispatcher_t* async, async_exception_t* exception,
95             zx_status_t status, const zx_port_packet_t* exception) {
96    printf("signal received: status=%d, kind=0x%x",
97           status, exception ? exception->type : 0);
98    if (status == ZX_OK) {
99        // ... process exception ...
100    }
101}
102
103zx_status_t ebind(async_exception_handler_t* handler,
104                  zx_handle_t task, uint32_t options,
105                  zx_async_exception_t* out_exception) {
106    async_dispatcher_t* async = async_get_default_dispatcher();
107    async_exception_t* exception = calloc(1, sizeof(async_exception_t));
108    exception->handler = handler;
109    exception->task = task;
110    exception->options = options;
111    zx_status_t status = async_bind_exception_port(async, exception);
112    if (status == ZX_OK) {
113        *out_exception = exception;
114    } else }
115        free(exception);
116    }
117    return status;
118}
119
120zx_status_t eunbind(async_exception_t* exception) {
121    async_dispatcher_t* async = async_get_default_dispatcher();
122    zx_status_t status = async_unbind_exception_port(dispatcher, exception);
123    free(exception);
124    return status;
125}
126```
127
128### Getting the current time
129
130The dispatcher represents time in the form of a `zx_time_t`.  In normal
131operation, values of this type represent a moment in the `ZX_CLOCK_MONOTONIC`
132time base.  However for unit testing purposes, dispatchers may use a synthetic
133time base instead.
134
135To make unit testing easier, prefer using `async_now()` to get the current
136time according the dispatcher's time base.
137
138See [async/time.h](include/lib/async/time.h) for details.
139
140### Posting tasks and getting the current time
141
142To schedule asynchronous tasks, the client prepares an `async_task_t`
143structure then calls `async_post_task()` to register it with the dispatcher.
144When the task comes due, the dispatcher invokes the handler.
145
146The client can post tasks from any thread but dispatch will occur
147on a thread of the dispatcher's choosing depending on its implementation.
148
149The client is responsible for ensuring that the task structure remains in
150memory until the task's handler runs or the task is successfully canceled using
151`async_cancel_task()`.
152
153See [async/task.h](include/lib/async/task.h) for details.
154
155```c
156#include <lib/async/task.h>     // for async_post_task()
157#include <lib/async/time.h>     // for async_now()
158#include <lib/async/default.h>  // for async_get_default_dispatcher()
159
160typedef struct {
161    async_task_t task;
162    void* data;
163} task_data_t;
164
165void handler(async_dispatcher_t* async, async_task_t* task, zx_status_t status) {
166    task_data_t* task_data = (task_data_t*)task;
167    printf("task deadline elapsed: status=%d, data=%p", status, task_data->data);
168    free(task_data);
169}
170
171zx_status_t schedule_work(void* data) {
172    async_dispatcher_t* async = async_get_default_dispatcher();
173    task_data_t* task_data = calloc(1, sizeof(task_data_t));
174    task_data->task.handler = handler;
175    task_data->task.deadline = async_now(async) + ZX_SEC(2);
176    task_data->data = data;
177    return async_post_task(async, &task_data->task);
178}
179```
180
181### Delivering packets to a receiver
182
183Occasionally it may be useful to register a receiver which will be the
184recipient of multiple data packets instead of allocating a separate task
185structure for each one.  The Zircon port takes care of storing the queued
186packet data contents until it is delivered.
187
188The client can queue packets from any thread but dispatch will occur
189on a thread of the dispatcher's choosing depending on its implementation.
190
191The client is responsible for ensuring that the receiver structure remains in
192memory until all queued packets have been delivered.
193
194See [async/receiver.h](include/lib/async/receiver.h) for details.
195
196```c
197#include <lib/async/receiver.h>  // for async_queue_packet()
198#include <lib/async/default.h>   // for async_get_default_dispatcher()
199
200void handler(async_dispatcher_t* async, async_receiver_t* receiver, zx_status_t status,
201             const zx_packet_user_t* data) {
202    printf("packet received: status=%d, data.u32[0]=%d", status, data ? data.u32[0] : 0);
203}
204
205const async_receiver_t receiver = {
206    .state = ASYNC_STATE_INIT,
207    .handler = handler;
208}
209
210zx_status_t send(const zx_packet_user_t* data) {
211    async_dispatcher_t* async = async_get_default_dispatcher();
212    return async_queue_packet(async, &receiver, data);
213}
214```
215
216## The default async dispatcher
217
218As a client of the async dispatcher, where should you get your `async_dispatcher_t*` from?
219
220The ideal answer is for the `async_dispatcher_t*` to be passed into your code when it is
221initialized.  However sometimes this becomes burdensome or isn't practical.
222
223For this reason, the `libasync-default.so` shared library provides functions
224for getting or setting a thread-local default `async_dispatcher_t*` using
225`async_get_default_dispatcher()` or `async_set_default_dispatcher()`.
226
227This makes it easy to retrieve the `async_dispatcher_t*` from the ambient environment
228by calling `async_get_default_dispatcher()`, which is used by many libraries.
229
230Message loop implementations should register themselves as the default
231dispatcher any threads they service.
232
233See [async/default.h](include/lib/async/default.h) for details.
234
235## Using the C++ helpers
236
237`libasync-cpp.a` includes helper classes such as `Wait`, `Task`, and `Receiver`
238which wrap the C API with a more convenient type safe interface for use
239in C++.
240
241Note that the C API can of course be used directly from C++ for special
242situations which may not be well addressed by the wrappers.
243
244## Implementing a dispatcher
245
246The `async_ops_t` interface is a low-level abstraction for asynchronous
247dispatchers.  You can make custom implementations of this interface to
248integrate clients of this library with your own dispatcher.
249
250It is possible to implement only some of the operations but this may cause
251incompatibilities with certain clients.
252
253See [async/dispatcher.h](include/lib/async/dispatcher.h) for details.
254