flux_future_create(3)
SYNOPSIS
#include <flux/core.h>
typedef void (*flux_future_init_f)(flux_future_t *f,
flux_reactor_t *r,
void *arg);
flux_future_t *flux_future_create (flux_future_init_f cb, void *arg);
void flux_future_fulfill (flux_future_t *f,
void *result,
flux_free_f free_fn);
void flux_future_fulfill_error (flux_future_t *f,
int errnum,
const char *errstr);
void flux_future_fulfill_with (flux_future_t *f, flux_future_t *p);
void flux_future_fatal_error (flux_future_t *f,
int errnum,
const char *errstr);
void *flux_future_aux_get (flux_future_t *f, const char *name);
int flux_future_aux_set (flux_future_t *f,
const char *name,
void *aux,
flux_free_f destroy);
void flux_future_set_reactor (flux_future_t *f, flux_t *h);
flux_reactor_t *flux_future_get_reactor (flux_future_t *f);
void flux_future_set_flux (flux_future_t *f, flux_t *h);
flux_t *flux_future_get_flux (flux_future_t *f);
Link with -lflux-core.
DESCRIPTION
See flux_future_get(3) for general functions that operate on futures. This page covers functions primarily used when building classes that return futures.
A Flux future represents some activity that may be completed with reactor watchers and/or message handlers. It is intended to be returned by other classes as a handle for synchronization and a container for results. This page describes the future interfaces used by such classes.
A class that returns a future usually provides a creation function that
internally calls flux_future_create()
, and may provide functions to
access class-specific result(s), that internally call flux_future_get(3).
The create function internally registers a flux_future_init_f
function that is called lazily by the future implementation to perform
class-specific reactor setup, such as installing watchers and message
handlers.
flux_future_create()
creates a future and registers the
class-specific initialization callback cb
, and an opaque argument
arg
that will be passed to cb
. The purpose of the initialization
callback is to set up class-specific watchers on a reactor obtained
with flux_future_get_reactor()
, or message handlers on a flux_t
handle obtained with flux_future_get_flux()
, or both.
flux_future_get_reactor()
and flux_future_get_flux()
return
different results depending on whether the initialization callback is
triggered by a user calling flux_future_then(3) or
flux_future_wait_for(3). The function may be triggered in one or
both contexts, at most once for each. The watchers or message
handlers must eventually call flux_future_fulfill()
,
flux_future_fulfill_error()
, or flux_future_fatal_error()
to
fulfill the future. See REACTOR CONTEXTS below for more information.
flux_future_fulfill()
fulfills the future, assigning an opaque
result
value with optional destructor free_fn
to the future.
A NULL result
is valid and also fulfills the future. The result
is contained within the future and can be accessed with flux_future_get(3)
as needed until the future is destroyed.
flux_future_fulfill_error()
fulfills the future, assigning an
errnum
value and an optional error string. After the future is
fulfilled with an error, flux_future_get(3) will return -1 with
errno
set to errnum
.
flux_future_fulfill_with()
fulfills the target future f
using a
fulfilled future p
. This function copies the pending result or error
from p
into f
, and adds read-only access to the aux
items
for p
from f
. This ensures that any get
method which requires
aux
items for p
will work with f
. This function takes a
reference to the source future p
, so it safe to call
flux_future_destroy(3) on p
after this call.
flux_future_fulfill_with()
returns -1 on error with errno
set on failure.
flux_future_fulfill()
, flux_future_fulfill_with()
, and
flux_future_fulfill_error()
can be called multiple times to queue
multiple results or errors. When callers access future results via
flux_future_get(3), results or errors will be returned in FIFO order.
It is an error to call flux_future_fulfill_with()
multiple times on
the same target future f
with a different source future p
.
flux_future_fatal_error()
fulfills the future, assigning an errnum
value and an optional error string. Unlike
flux_future_fulfill_error()
this fulfillment can only be called once
and takes precedence over all other fulfillments. It is used for
catastrophic error paths in future fulfillment.
flux_future_aux_set()
attaches application-specific data
to the parent object f
. It stores data aux
by key name
,
with optional destructor destroy. The destructor, if non-NULL,
is called when the parent object is destroyed, or when
key
is overwritten by a new value. If aux
is NULL,
the destructor for a previous value, if any is called,
but no new value is stored. If name
is NULL,
aux
is stored anonymously.
flux_future_aux_get()
retrieves application-specific data
by name
. If the data was stored anonymously, it
cannot be retrieved.
Names beginning with "flux::" are reserved for internal use.
flux_future_set_reactor()
may be used to associate a Flux reactor
with a future. The reactor (or a temporary one, depending on the context)
may be retrieved using flux_future_get_reactor()
.
flux_future_set_flux()
may be used to associate a Flux broker handle
with a future. The handle (or a clone associated with a temporary reactor,
depending on the context) may be retrieved using flux_future_get_flux()
.
Futures may "contain" other futures, to arbitrary depth. That is, an init callback may create futures and use their continuations to fulfill the containing future in the same manner as reactor watchers and message handlers.
REACTOR CONTEXTS
Internally, a future can operate in two reactor contexts. The initialization
callback may be called in either or both contexts, depending on which
synchronization functions are called by the user.
flux_future_get_reactor()
and flux_future_get_flux()
return a
result that depends on which context they are called from.
When the user calls flux_future_then(3), this triggers a call to the
initialization callback. The callback would typically call
flux_future_get_reactor()
and/or flux_future_get_flux()
to obtain
the reactor or flux_t
handle to be used to set up watchers or message
handlers. In this context, the reactor or flux_t
handle are exactly
the ones passed to flux_future_set_reactor()
and
flux_future_set_flux()
.
When the user calls flux_future_wait_for(3), this triggers the creation
of a temporary reactor, then a call to the initialization callback.
The temporary reactor allows these functions to wait only for the future's
events, without allowing unrelated watchers registered in the main reactor
to run, which might complicate the application's control flow. In this
context, flux_future_get_reactor()
returns the temporary reactor, not
the one passed in with flux_future_set_reactor()
.
flux_future_get_flux()
returns a temporary flux_t
handle cloned
from the one passed to flux_future_set_flux()
, and associated with the
temporary reactor.
After the internal reactor returns, any messages unmatched by the dispatcher
on the cloned handle are requeued in the main flux_t
handle with
flux_dispatch_requeue()
.
Since the init callback may be made in either reactor context (at most once
each), and is unaware of which context that is, it should take care when
managing any context-specific state not to overwrite the state from a prior
call. The ability to attach objects with destructors anonymously to the future
with flux_future_aux_set()
may be useful for managing the life cycle
of reactor watchers and message handlers created by init callbacks.
RETURN VALUE
flux_future_create()
returns a future on success. On error, NULL is
returned and errno
is set appropriately.
flux_future_aux_set()
returns zero on success. On error, -1 is
returned and errno
is set appropriately.
flux_future_aux_get()
returns the requested object on success. On
error, NULL is returned and errno
is set appropriately.
flux_future_get_flux()
returns a flux_t
handle on success.
On error, NULL is returned and errno
is set appropriately.
flux_future_get_reactor()
returns a flux_reactor_t
on success.
On error, NULL is returned and errno
is set appropriately.
flux_future_fulfill_with()
returns zero on success. On error, -1 is
returned with errno
set to EINVAL if either f
or p
is
NULL, or f
and p
are the same, EAGAIN if the future p
is
not ready, or EEXIST if the function is called multiple times with different
p
.
ERRORS
- ENOMEM
Out of memory.
- EINVAL
Invalid argument.
- ENOENT
The requested object is not found.
- EAGAIN
The requested operation is not ready. For
flux_future_fulfill_with()
, the target futurep
is not fulfilled.- EEXIST
flux_future_fulfill_with()
was called multiple times with a different target futurep
.
RESOURCES
Flux: http://flux-framework.org
Flux RFC: https://flux-framework.readthedocs.io/projects/flux-rfc
Issue Tracker: https://github.com/flux-framework/flux-core/issues