diff --git a/doc/man3/flux_future_create.adoc b/doc/man3/flux_future_create.adoc index fc7c4e2a09ae..e22b72bb89de 100644 --- a/doc/man3/flux_future_create.adoc +++ b/doc/man3/flux_future_create.adoc @@ -13,10 +13,9 @@ SYNOPSIS #include typedef void (*flux_future_init_f)(flux_future_t *f, - flux_reactor_t *r, void *arg); + flux_reactor_t *r, void *arg); - flux_future_t *flux_future_create (flux_reactor_t *r, - flux_future_init_f cb, 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); @@ -28,6 +27,10 @@ SYNOPSIS 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); @@ -39,29 +42,30 @@ DESCRIPTION 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. -Such a class provides two user-facing functions, one to initiate the -activity and return a future which internally calls `flux_future_create()`, -and one to access class-specific result(s), which internally calls -`flux_future_get()`. The class also provides 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. This page describes the future interfaces used by such classes. +This page describes the future interfaces used by such classes. Class users and users seeking an introduction to Flux futures are referred to `flux_future_then(3)`. -`flux_future_create()` creates a future, associates a reactor with it, - and registers the class-specific initialization callback _cb_, and an -opaque argument _arg_ that will be passed to _cb_. The callback sets -up class-specific watchers on the reactor to handle asynchronous events. -The watchers must eventually call `flux_future_fulfill()` or -`flux_future_fulfill_error()` to fulfill the future. The callback may -occur in one or both of two contexts. A call in the first context occurs -when the user calls `flux_future_then()`. A call in the second context -occurs when the user (or `flux_future_get()`) calls `flux_future_wait_for()`. -In the former case, the callback receives the reactor _r_ passed to -`flux_future_create()`. In the latter case, it receives a temporary reactor -created within the `flux_future_wait_for()` implementation. See REACTOR -CONTEXTS below for more information. +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()`. +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()` or `flux_future_wait_for()`. +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()` +or `flux_future_fulfill_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. @@ -79,10 +83,13 @@ retrieves an object by _name_. Destructors are called when the future is destroyed. Objects may be stored anonymously under a NULL _name_ to be scheduled for destruction without the option of retrieval. +`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 may be retrieved from within an init callback using -`flux_future_get_flux()` and used to set up message handlers that -fulfill the future in the same manner as described for reactor watchers. +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 @@ -93,22 +100,31 @@ handlers. REACTOR CONTEXTS ---------------- -Internally, a future can operate in two reactor contexts. The init +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. - -The main reactor context involves the reactor passed to `flux_future_create()`. -This reactor is expected to be run or re-entered by the user, and can process -the future's watchers in parallel with other watchers registered by the -application. The call to `flux_future_then()` triggers the init callback -in this context. - -Alternatively, an internal reactor is created when `flux_future_wait_for()` -is called before the future is complete. The separate 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. After the internal reactor is created, the -init callback is made in this context. +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()`, 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()`, 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 @@ -118,19 +134,6 @@ with `flux_future_aux_set()` may be useful for managing the life cycle of reactor watchers and message handlers created by init callbacks. -MESSAGE HANDLERS ----------------- - -To allow message handlers to be registered in either reactor context, -`flux_future_get_flux()` is context sensitive. If called in the main -reactor context, it directly returns the broker handle registered with -`flux_future_set_flux()`. If called in the internal reactor context, -it returns a clone of that handle, obtained with `flux_clone()`, and -associated with the internal reactor. After the internal reactor returns, -any message unmatched by the dispatcher on the cloned handle are requeued -in the handle with `flux_dispatch_requeue()`. - - RETURN VALUE ------------ @@ -146,6 +149,9 @@ 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. + ERRORS ------