Scroll to navigation

MINIASYNC_FUTURE(7) MINIASYNC Programmer's Manual MINIASYNC_FUTURE(7)

NAME

miniasync_future - Future API for miniasync library

SYNOPSIS

#include <libminiasync.h>
typedef enum future_state (*future_task_fn)(struct future_context *context,

struct future_notifier *notifier); typedef void (*future_waker_wake_fn)(void *data); typedef void (*future_map_fn)(struct future_context *lhs,
struct future_context *rhs, void *arg); typedef void (*future_init_fn)(void *future,
struct future_context *chain_fut, void *arg); typedef int (*future_has_property_fn)(void *future,
enum future_property property); enum future_state {
FUTURE_STATE_IDLE,
FUTURE_STATE_COMPLETE,
FUTURE_STATE_RUNNING, }; struct future_context {
size_t data_size;
size_t output_size;
enum future_state state;
uint32_t padding; }; struct future_waker {
void *data;
future_waker_wake_fn wake; }; struct future_poller {
uint64_t *ptr_to_monitor; }; enum future_notifier_type {
FUTURE_NOTIFIER_NONE,
FUTURE_NOTIFIER_WAKER,
FUTURE_NOTIFIER_POLLER, }; struct future_notifier {
struct future_waker waker;
struct future_poller poller;
enum future_notifier_type notifier_used;
uint32_t padding; }; enum future_property {
FUTURE_PROPERTY_ASYNC, }; FUTURE(_name, _data_type, _output_type) FUTURE_INIT(_futurep, _taskfn) FUTURE_INIT_COMPLETE(_futurep) FUTURE_CHAIN_ENTRY(_future_type, _name) FUTURE_CHAIN_ENTRY_LAST(_future_type, _name) FUTURE_CHAIN_ENTRY_INIT(_entry, _fut, _map, _map_arg) FUTURE_CHAIN_ENTRY_LAZY_INIT(_entry, _init, _init_arg, _map, _map_arg) FUTURE_CHAIN_ENTRY_IS_INITIALIZED(_entry) FUTURE_CHAIN_INIT(_futurep) FUTURE_AS_RUNNABLE(_futurep) FUTURE_OUTPUT(_futurep) FUTURE_BUSY_POLL(_futurep) FUTURE_WAKER_WAKE(_wakerp)

For general description of future API, see miniasync_future(7).

DESCRIPTION

Future is an abstract type representing a task, or a collection of tasks, that can be executed incrementally by polling until the operation is complete. Futures are typically meant to be implemented by library developers and then used by applications to concurrently run multiple, possibly unrelated, tasks.

A future contains the following context: * current state of execution for the future * a function pointer for the task * structure for data which is the required state needed to perform the task * structure for output to store the result of the task * the size of the data and output structures (both can be 0) * a pointer for the property checking function which checks if the future has a custom property

A future definition must begin with an instance of the struct future type, which contains all common metadata for all futures, followed by the structures for data and output. The library provides convenience macros to simplify the definition of user-defined future types. See MACROS section for details.

Applications must call the future_poll(3) method to make progress on the task associated with the future. This function will perform an implementation-defined operation towards completing the task and return the future’s current state. Futures are generally safe to poll until they are complete. Unless the documentation for a specific future implementation indicates otherwise, futures can be moved in memory and don’t always have to be polled by the same thread.

Optionally, future implementations can accept notifiers for use in polling. Notifiers can be useful to avoid busy polling when the future is waiting for some asynchronous operation to finish or for some resource to become available. Currently, miniasync(7) supports only waker notifier type.

A waker is a tuple composed of a function pointer and a data context pointer. If a waker is supplied and consumed by a future, it will call the function with its data pointer when the future can be polled again to make further progress. The caller needs to make sure that the waker is safe to call until the future is complete or until it supplies a different waker to the future_poll(3) method. The waker implementation needs to be thread-safe.

A future implementation supporting FUTURE_NOTIFIER_WAKER type of notifier can use a **FUTURE_WAKER_WAKE(_wakerp)** macro to signal the caller that some progress can be made and the future should be polled again.

Futures can contain custom properties. Information, whether the future contains the property or not, is returned by the future_has_property function. Concrete implementation of the future_has_property_fn function should return the information, whether given future property applies to the future. Individual futures can be initialized using FUTURE_INIT_EXT(_futurep, _taskfn, _propertyfn) macro to set the property checking function. Futures initialized regularly have no properties applied.

Supported properties: * FUTURE_PROPERTY_ASYNC property indicates that the future is asynchronous.

For more information about the usage of future API, see examples directory in miniasync repository <https://github.com/pmem/miniasync>.

MACROS

FUTURE(_name, _data_type, _output_type) macro defines a future structure with _name as its name. Besides internal data needed by the future API, the defined structure contains data member of _data_type type and output member of _output_type type. User can provide the data that may later be retrieved in the future task implementation using future_context_get_data(3) function. Similarly, the output of the future task can be retrieved using future_context_get_output(3) function. Combined size of data and output structures can be retrieved using future_context_get_size(3) function. When the user has no need for input or output data, _data_type and _output_type can be defined as empty structures.

FUTURE_INIT(_futurep, _taskfn) macro assigns task function _taskfn to the future pointed by _futurep. Task function must be of the future_task_fn type.

FUTURE_INIT_EXT(_futurep, _taskfn, _propertyfn) macro assigns task function _taskfn and property checking function _propertyfn to the future pointed by _futurep. Task function must be of the future_task_fn type and the property checking function must be of the type future_has_property_fn.

FUTURE_INIT_COMPLETE(_futurep) macro instantiates a new already completed future with no assigned task. This is helpful for handling initialization errors during future creation or simply for convenience in instantly ready futures.

FUTURE_CHAIN_ENTRY(_future_type, _name) macro defines the future chain entry of the _future_type type named _name. Future chain entries are defined as the members of chained future data structure using this macro. Chained future can be composed of multiple future chain entries that will be executed sequentially in the order they were defined.

FUTURE_CHAIN_ENTRY_LAST(_future_type, _name) macro can be optionally used to indicate the last future in a chain. This lets software to include additional state inside of the _data_type since otherwise the chain task implementation would not be able to differentiate between an entry and other data.

FUTURE_CHAIN_ENTRY_INIT(_entry, _fut, _map, _map_arg) macro initializes the future chain entry pointed by _entry. It requires pointer to the future instance _fut, address of the mapping function _map and the pointer to the argument for the mapping function _map_arg. _fut can either be the instance of the future defined using FUTURE(_name, _data_type, _output_type) macro or a virtual data mover future. _map function must be of the future_map_fn type and is an optional parameter. map function should define the mapping behavior of the data and output structures between chained future entry _entry that has finished and the chained future entry that is about to start its execution. Chained future instance must initialize all of its future chain entries using this macro.

FUTURE_CHAIN_ENTRY_LAZY_INIT(_entry, _init, _init_arg, _map, _map_arg) macro initializes the future chain entry pointed by _entry but it does not initialize its underlying future. Instead it uses function _init and its argument _init_arg to instantiate the future right before it’s needed. This lets software instantiate futures with arguments derived from the results of previous entries in the chain. The _map and _map_arg variables behave the same as in FUTURE_CHAIN_ENTRY_INIT.

FUTURE_CHAIN_ENTRY_IS_INITIALIZED(_entry) macro checks if the future chain entry, pointed by _entry, is already initialized (either lazily or regularly). If it is initialized, its structure can be safely accessed and used.

FUTURE_CHAIN_INIT(_futurep) macro initializes the chained future at the address _futurep.

FUTURE_AS_RUNNABLE(_futurep) macro returns pointer to the runnable form of the future pointed by _futurep. Runnable form of the future is required as an argument in runtime_wait(3) and runtime_wait_multiple(3) functions.

FUTURE_OUTPUT(_futurep) macro returns the output of the future pointed by _futurep.

FUTURE_BUSY_POLL(_futurep) repeatedly polls the future pointed by _futurep until it completes its execution. This macro does not use optimized polling.

FUTURE_WAKER_WAKE(_wakerp) macro performs implementation-defined wake operation. It takes a pointer to the waker structure of struct future_waker type.

SEE ALSO

future_context_get_data(3), future_context_get_output(3), future_context_get_size(3), future_poll(3), runtime_wait(3), runtime_wait_multiple(3) miniasync(7), miniasync_runtime(7), miniasync_vdm(7) and <https://pmem.io>

2022-09-04 MINIASYNC - miniasync version 0.2.1