| # zxio |
| |
| The zxio client library provides an object oriented abstraction on top of basic |
| I/O primitives such as files, pipes, directories, and sockets. This library is |
| intended for use in low-level system libraries such as fdio and language |
| runtimes to provide a minimal abstraction over different representations and |
| protocols used for common primitives. |
| |
| Internally, this library uses the FIDL fuchsia.io* family of protocols and |
| Zircon syscalls. |
| |
| # Objects |
| |
| The zxio library is based on objects of type zxio_t. An object represents a |
| single logical entity and a set of operations that can be performed on that |
| entity. Internally an object may contain one or more Zircon handles to kernel |
| objects. |
| |
| ## Storage and lifetime of objects |
| |
| The caller of the zxio library is responsible for providing storage for zxio |
| objects and is responsible for their lifetime. A zxio object lives within an |
| instance of the zxio_storage_t type. |
| |
| ## Kernel objects |
| |
| A zxio object may allocate and retain ownership of one or more kernel objects |
| during the course of operation. Destroying an object will close all handles |
| owned by a zxio object. Calling `zxio_release()` will close all handles except for |
| the extracted primary object handle. |
| |
| Functions with `zx_handle_t` parameters take ownership of the provided handles in |
| all cases including errors unless the function documentation specifically states |
| otherwise. |
| |
| Functions with `zx_handle_t*` out parameters will do one of the following unless |
| the function documentation specifically states otherwise: |
| |
| - Store a valid handle value into the provided address and return success. The |
| caller has ownership of the handle in this case. |
| - Store the value `ZX_HANDLE_INVALID` into the provided address and return an |
| error code. |
| - Do not store anything into the provided address and return an error code. |
| |
| ## Object types |
| |
| The zxio library has an extensible set of object types. The library provides |
| many object types internally and allows users of the library to define their own |
| types by implementing the zxio ops table defined in zxio/ops.h. Custom object |
| implementers should adhere to the threading model for those objects. |
| |
| ## Threading model |
| |
| Operations on zxio objects are thread-safe unless otherwise noted below. The |
| zxio library will internally synchronize any local state changes. |
| |
| ### Creation and destruction |
| |
| A zxio object must be fully created with one of the `zxio_create..()` functions |
| before it can be used. |
| |
| A zxio object is destroyed with the `zxio_close()` call. The caller is responsible |
| for ensuring that the zxio object is not in use on any thread before calling |
| `zxio_close()`. The `zxio_close()` operations always destroys the object and frees |
| any resources associated with the object even in error cases. The close |
| operation cannot be retried. |
| |
| The storage underlying the zxio object should not be modified except by the zxio |
| library or custom object implementations and must remain valid until after |
| `zxio_close()` returns. |
| |
| ### Intrusive and compound operations |
| |
| Some zxio operations provide access to or rely on the internal state of the |
| object and have additional considerations. |
| |
| - `zxio_release()` extracts a handle from the zxio object and is partially |
| destructive on the object. The caller is responsible for ensuring that the zxio |
| object is not in use on any thread before calling `zxio_release()`. After |
| calling `zxio_release()`, the only operation that is safe to perform on the zxio |
| object is `zxio_close()`. `zxio_close()` must be called before the storage |
| underlying the object is deallocated. |
| |
| - `zxio_borrow()` returns a handle to the zxio object's primary object if it |
| exists. The caller must take care to ensure that they do not close this handle |
| and that any operations they perform are safe with concurrent operations on the |
| object. |
| |
| - `zxio_dirent_iterator_init()` creates an iterator object tied to a directory |
| object. The directory object must outlive the iterator object. |
| |
| - `zxio_watch_directory()` initiates a watch operation tied to a directory object. |
| The operation must conclude before the directory can be destroyed. |
| |
| ## Blocking and cancellation |
| |
| Many zxio operations are synchronized with a kernel object and possibly remote |
| server before returning. These operations will return the error |
| ZX_ERR_WOULD_BLOCK if the operation is unable to make progress in the object's |
| current state. Such operations may block if the remote server is unresponsive. |
| They should not block based on the object's internal state. |
| |
| Operations which will never synchronize with a remote server are |
| documented as such. Some operations also expose a variant with the suffix |
| `_async` to indicate that they do not block and that the caller is responsible |
| for completing the remainder of the operation. `zxio_open_async()` is an |
| example of such an operation. It solicits an event from the server backing the |
| opened object into a provided channel object. The caller can wait for the |
| channel to become readable using an asynchronous waiting facility such as a |
| `zx_port_wait()` and then call `zxio_open_with_on_open()` to process the event |
| when it is ready, or simply call `zxio_open_with_on_open()` to block until an |
| event is ready. |
| |
| The zxio library does not currently provide any mechanism for canceling pending |
| or concurrent blocking operations on an object. |
| |
| ## Asynchronously waiting for state changes |
| |
| The zxio library supports asynchronously waiting for objects to change state. |
| This can be used to defer operations until they are likely to make progress. To |
| use this facility: |
| |
| 1. Call `zxio_wait_begin()` with a set of states of interest. This will produce |
| a `zx_handle_t` value and a `zx_signals_t` value. Note that this operation does |
| not transfer ownership of the handle. |
| 2. Register a wait on the handle + signals tuple with `zx_object_async_wait()` |
| or another Zircon waiting operation. |
| 3. When the wait completes, call `zxio_wait_end()` with the values from kernel. |
| This will produce a `zxio_signals_t` value reflecting the object's new state. |
| 4. Make calls based on the new state. |
| |
| As the handle value produced by `zxio_wait_begin()` is borrowed from the zxio |
| object, it is unsafe to destroy the zxio object or release and close the |
| object's primary handle and then register and async wait. |
| |
| This can be used to implement blocking calls by attempting the operation and |
| then blocking with `zx_object_wait_one()` if the operation returns |
| `ZX_ERR_WOULD_BLOCK`. |
| |
| # Allocations, buffers, and strings |
| |
| ## Heap allocations |
| |
| The zxio library currently allocates internal heap buffers for some operations. |
| These allocations are internal to the library and not exposed to callers. Custom |
| object implementations should avoid heap allocations where possible and maintain |
| ownership internal to the object when not. |
| |
| TODO(https://fxbug.com/91172): Remove all of the heap allocations from inside |
| zxio and update this text. |
| |
| ## Buffers |
| |
| Many zxio operations read or write to caller allocated buffers. The caller must |
| take care to ensure that these buffers are of the required size and alignment |
| and that they remain valid for the duration of the call. |
| |
| ## Stack usage |
| |
| The zxio library attempts to use a limited amount of stack space to be usable in |
| as many situations as possible. Zxio does not perform any dynamically sized |
| stack allocations. There is currently no concrete upper bound on the stack usage |
| of the zxio library. |
| |
| |
| ## Strings |
| |
| The zxio library represents path components as strings with a pointer to a |
| buffer and an length. Path components cannot contain embedded nulls. The zxio library |
| does not require or set a null terminator. |
| |
| When interfacing with C-style strings, compute a string length explicitly for |
| input parameters and allocate space for a null terminator for output parameters. |
| |
| # Linkage |
| |
| The zxio library does not maintain internal static state and can be used as a |
| static library. It internally uses the C++ standard library. |
| |
| ## zxio_standalone |
| |
| libzxio_standalone.so is provided as a standalone shared library version of the |
| zxio with most dependencies statically linked in (including the C++ standard |
| library). This library depends dynamically on a subset of the C standard |
| library, many vVDSO calls, and the __zx_panic symbol. The exact list of symbol |
| dependencies is listed in zxio_standalone.imported_symbols.allowlist. |