tevent  0.9.31
Typedefs | Enumerations | Functions
The tevent request functions.

A tevent_req represents an asynchronous computation. More...

Typedefs

typedef void(* tevent_req_fn) (struct tevent_req *req)
 A tevent request callback function. More...
 
typedef char *(* tevent_req_print_fn) (struct tevent_req *req, TALLOC_CTX *ctx)
 The print function which can be set for a tevent async request. More...
 
typedef bool(* tevent_req_cancel_fn) (struct tevent_req *req)
 A typedef for a cancel function for a tevent request. More...
 
typedef void(* tevent_req_cleanup_fn) (struct tevent_req *req, enum tevent_req_state req_state)
 A typedef for a cleanup function for a tevent request. More...
 

Enumerations

enum  tevent_req_state {
  TEVENT_REQ_INIT, TEVENT_REQ_IN_PROGRESS, TEVENT_REQ_DONE, TEVENT_REQ_USER_ERROR,
  TEVENT_REQ_TIMED_OUT, TEVENT_REQ_NO_MEMORY, TEVENT_REQ_RECEIVED
}
 An async request moves from TEVENT_REQ_INIT to TEVENT_REQ_IN_PROGRESS. More...
 

Functions

void tevent_req_set_callback (struct tevent_req *req, tevent_req_fn fn, void *pvt)
 Set an async request callback. More...
 
void * tevent_req_callback_data (struct tevent_req *req, #type)
 Get the private data cast to the given type for a callback from a tevent request structure. More...
 
void * tevent_req_callback_data_void (struct tevent_req *req)
 Get the private data for a callback from a tevent request structure. More...
 
void * tevent_req_data (struct tevent_req *req, #type)
 Get the private data from a tevent request structure. More...
 
void tevent_req_set_print_fn (struct tevent_req *req, tevent_req_print_fn fn)
 This function sets a print function for the given request. More...
 
char * tevent_req_default_print (struct tevent_req *req, TALLOC_CTX *mem_ctx)
 The default print function for creating debug messages. More...
 
char * tevent_req_print (TALLOC_CTX *mem_ctx, struct tevent_req *req)
 Print an tevent_req structure in debug messages. More...
 
void tevent_req_set_cancel_fn (struct tevent_req *req, tevent_req_cancel_fn fn)
 This function sets a cancel function for the given tevent request. More...
 
bool tevent_req_cancel (struct tevent_req *req)
 Try to cancel the given tevent request. More...
 
void tevent_req_set_cleanup_fn (struct tevent_req *req, tevent_req_cleanup_fn fn)
 This function sets a cleanup function for the given tevent request. More...
 
struct tevent_req * tevent_req_create (TALLOC_CTX *mem_ctx, void **pstate, #type)
 Create an async tevent request. More...
 
bool tevent_req_set_endtime (struct tevent_req *req, struct tevent_context *ev, struct timeval endtime)
 Set a timeout for an async request. More...
 
void tevent_req_reset_endtime (struct tevent_req *req)
 Reset the timer set by tevent_req_set_endtime. More...
 
void tevent_req_notify_callback (struct tevent_req *req)
 Call the notify callback of the given tevent request manually. More...
 
void tevent_req_done (struct tevent_req *req)
 An async request has successfully finished. More...
 
bool tevent_req_error (struct tevent_req *req, uint64_t error)
 An async request has seen an error. More...
 
bool tevent_req_nomem (const void *p, struct tevent_req *req)
 Helper function for nomem check. More...
 
void tevent_req_oom (struct tevent_req *req)
 Indicate out of memory to a request. More...
 
struct tevent_req * tevent_req_post (struct tevent_req *req, struct tevent_context *ev)
 Finish a request before the caller had the change to set the callback. More...
 
void tevent_req_defer_callback (struct tevent_req *req, struct tevent_context *ev)
 Finish multiple requests within one function. More...
 
bool tevent_req_is_in_progress (struct tevent_req *req)
 Check if the given request is still in progress. More...
 
bool tevent_req_poll (struct tevent_req *req, struct tevent_context *ev)
 Actively poll for the given request to finish. More...
 
bool tevent_req_is_error (struct tevent_req *req, enum tevent_req_state *state, uint64_t *error)
 Get the tevent request state and the actual error set by tevent_req_error. More...
 
void tevent_req_received (struct tevent_req *req)
 Use as the last action of a _recv() function. More...
 
struct tevent_req * tevent_wakeup_send (TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct timeval wakeup_time)
 Create a tevent subrequest at a given time. More...
 
bool tevent_wakeup_recv (struct tevent_req *req)
 Check if the wakeup has been correctly executed. More...
 

Detailed Description

A tevent_req represents an asynchronous computation.

The tevent_req group of API calls is the recommended way of programming async computations within tevent. In particular the file descriptor (tevent_add_fd) and timer (tevent_add_timed) events are considered too low-level to be used in larger computations. To read and write from and to sockets, Samba provides two calls on top of tevent_add_fd: tstream_read_packet_send/recv and tstream_writev_send/recv. These requests are much easier to compose than the low-level event handlers called from tevent_add_fd.

A lot of the simplicity tevent_req has brought to the notoriously hairy async programming came via a set of conventions that every async computation programmed should follow. One central piece of these conventions is the naming of routines and variables.

Every async computation needs a name (sensibly called "computation" down from here). From this name quite a few naming conventions are derived.

Every computation that requires local state needs a

struct computation_state {
int local_var;
};

Even if no local variables are required, such a state struct should be created containing a dummy variable. Quite a few helper functions and macros (for example tevent_req_create()) assume such a state struct.

An async computation is started by a computation_send function. When it is finished, its result can be received by a computation_recv function. For an example how to set up an async computation, see the code example in the documentation for tevent_req_create() and tevent_req_post(). The prototypes for _send and _recv functions should follow some conventions:

struct tevent_req *computation_send(TALLOC_CTX *mem_ctx,
struct tevent_req *ev,
... further args);
int computation_recv(struct tevent_req *req, ... further output args);

The "int" result of computation_recv() depends on the result the sync version of the function would have, "int" is just an example here.

Another important piece of the conventions is that the program flow is interrupted as little as possible. Because a blocking sub-computation requires that the flow needs to continue in a separate function that is the logical sequel of some computation, it should lexically follow sending off the blocking sub-computation. Setting the callback function via tevent_req_set_callback() requires referencing a function lexically below the call to tevent_req_set_callback(), forward declarations are required. A lot of the async computations thus begin with a sequence of declarations such as

static void computation_step1_done(struct tevent_req *subreq);
static void computation_step2_done(struct tevent_req *subreq);
static void computation_step3_done(struct tevent_req *subreq);

It really helps readability a lot to do these forward declarations, because the lexically sequential program flow makes the async computations almost as clear to read as a normal, sync program flow.

It is up to the user of the async computation to talloc_free it after it has finished. If an async computation should be aborted, the tevent_req structure can be talloc_free'ed. After it has finished, it should talloc_free'ed by the API user.

Typedef Documentation

§ tevent_req_cancel_fn

typedef bool(* tevent_req_cancel_fn) (struct tevent_req *req)

A typedef for a cancel function for a tevent request.

Parameters
[in]reqThe tevent request calling this function.
Returns
True if the request could be canceled, false if not.

§ tevent_req_cleanup_fn

typedef void(* tevent_req_cleanup_fn) (struct tevent_req *req, enum tevent_req_state req_state)

A typedef for a cleanup function for a tevent request.

Parameters
[in]reqThe tevent request calling this function.
[in]req_stateThe current tevent_req_state.

§ tevent_req_fn

typedef void(* tevent_req_fn) (struct tevent_req *req)

A tevent request callback function.

Parameters
[in]reqThe tevent async request which executed this callback.

§ tevent_req_print_fn

typedef char*(* tevent_req_print_fn) (struct tevent_req *req, TALLOC_CTX *ctx)

The print function which can be set for a tevent async request.

Parameters
[in]reqThe tevent async request.
[in]ctxA talloc memory context which can be uses to allocate memory.
Returns
An allocated string buffer to print.

Example:

static char *my_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
{
struct my_data *data = tevent_req_data(req, struct my_data);
char *result;
result = tevent_req_default_print(mem_ctx, req);
if (result == NULL) {
return NULL;
}
return talloc_asprintf_append_buffer(result, "foo=%d, bar=%d",
data->foo, data->bar);
}

Enumeration Type Documentation

§ tevent_req_state

An async request moves from TEVENT_REQ_INIT to TEVENT_REQ_IN_PROGRESS.

All other states are valid after a request has finished.

Enumerator
TEVENT_REQ_INIT 

We are creating the request.

TEVENT_REQ_IN_PROGRESS 

We are waiting the request to complete.

TEVENT_REQ_DONE 

The request is finished successfully.

TEVENT_REQ_USER_ERROR 

A user error has occurred.

The user error has been indicated by tevent_req_error(), it can be retrieved via tevent_req_is_error().

TEVENT_REQ_TIMED_OUT 

Request timed out after the timeout set by tevent_req_set_endtime.

TEVENT_REQ_NO_MEMORY 

An internal allocation has failed, or tevent_req_nomem has been given a NULL pointer as the first argument.

TEVENT_REQ_RECEIVED 

The request has been received by the caller.

No further action is valid.

Function Documentation

§ tevent_req_callback_data()

void* tevent_req_callback_data ( struct tevent_req *  req,
type 
)

Get the private data cast to the given type for a callback from a tevent request structure.

static void computation_done(struct tevent_req *subreq) {
struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
struct computation_state *state = tevent_req_data(req, struct computation_state);
.... more things, eventually maybe call tevent_req_done(req);
}
Parameters
[in]reqThe structure to get the callback data from.
[in]typeThe type of the private callback data to get.
Returns
The type casted private data set NULL if not set.

§ tevent_req_callback_data_void()

void* tevent_req_callback_data_void ( struct tevent_req *  req)

Get the private data for a callback from a tevent request structure.

Parameters
[in]reqThe structure to get the callback data from.
[in]reqThe structure to get the data from.
Returns
The private data or NULL if not set.

§ tevent_req_cancel()

bool tevent_req_cancel ( struct tevent_req *  req)

Try to cancel the given tevent request.

This function can be used to cancel the given request.

It is only possible to cancel a request when the implementation has registered a cancel function via the tevent_req_set_cancel_fn().

Parameters
[in]reqThe request to use.
Returns
This function returns true is the request is cancelable, othererwise false is returned.
Note
Even if the function returns true, the caller need to wait for the function to complete normally. Only the _recv() function of the given request indicates if the request was really canceled.

§ tevent_req_create()

struct tevent_req* tevent_req_create ( TALLOC_CTX *  mem_ctx,
void **  pstate,
type 
)

Create an async tevent request.

The new async request will be initialized in state TEVENT_REQ_IN_PROGRESS.

struct tevent_req *req;
struct computation_state *state;
req = tevent_req_create(mem_ctx, &state, struct computation_state);

Tevent_req_create() allocates and zeros the state variable as a talloc child of its result. The state variable should be used as the talloc parent for all temporary variables that are allocated during the async computation. This way, when the user of the async computation frees the request, the state as a talloc child will be free'd along with all the temporary variables hanging off the state.

Parameters
[in]mem_ctxThe memory context for the result.
[in]pstatePointer to the private request state.
[in]typeThe name of the request.
Returns
A new async request. NULL on error.

§ tevent_req_data()

void* tevent_req_data ( struct tevent_req *  req,
type 
)

Get the private data from a tevent request structure.

When the tevent_req has been created by tevent_req_create, the result of tevent_req_data() is the state variable created by tevent_req_create() as a child of the req.

Parameters
[in]reqThe structure to get the private data from.
[in]typeThe type of the private data
Returns
The private data or NULL if not set.

§ tevent_req_default_print()

char* tevent_req_default_print ( struct tevent_req *  req,
TALLOC_CTX *  mem_ctx 
)

The default print function for creating debug messages.

The function should not be used by users of the async API, but custom print function can use it and append custom text to the string.

Parameters
[in]reqThe request to be printed.
[in]mem_ctxThe memory context for the result.
Returns
Text representation of request.

§ tevent_req_defer_callback()

void tevent_req_defer_callback ( struct tevent_req *  req,
struct tevent_context *  ev 
)

Finish multiple requests within one function.

Normally tevent_req_notify_callback() and all wrappers (e.g. tevent_req_done() and tevent_req_error()) need to be the last thing an event handler should call. This is because the callback is likely to destroy the context of the current function.

If a function wants to notify more than one caller, it is dangerous if it just triggers multiple callbacks in a row. With tevent_req_defer_callback() it is possible to set an event context that will be used to defer the callback via an immediate event (similar to tevent_req_post()).

struct complete_state {
struct tevent_context *ev;
struct tevent_req **reqs;
};
void complete(struct complete_state *state)
{
size_t i, c = talloc_array_length(state->reqs);
for (i=0; i < c; i++) {
tevent_req_defer_callback(state->reqs[i], state->ev);
tevent_req_done(state->reqs[i]);
}
}
Parameters
[in]reqThe finished request.
[in]evThe tevent_context for the immediate event.
Returns
The given request will be returned.

§ tevent_req_done()

void tevent_req_done ( struct tevent_req *  req)

An async request has successfully finished.

This function is to be used by implementors of async requests. When a request is successfully finished, this function calls the user's completion function.

Parameters
[in]reqThe finished request.

§ tevent_req_error()

bool tevent_req_error ( struct tevent_req *  req,
uint64_t  error 
)

An async request has seen an error.

This function is to be used by implementors of async requests. When a request can not successfully completed, the implementation should call this function with the appropriate status code.

If error is 0 the function returns false and does nothing more.

Parameters
[in]reqThe request with an error.
[in]errorThe error code.
Returns
On success true is returned, false if error is 0.
int error = first_function();
if (tevent_req_error(req, error)) {
return;
}
error = second_function();
if (tevent_req_error(req, error)) {
return;
}
return;

§ tevent_req_is_error()

bool tevent_req_is_error ( struct tevent_req *  req,
enum tevent_req_state state,
uint64_t *  error 
)

Get the tevent request state and the actual error set by tevent_req_error.

int computation_recv(struct tevent_req *req, uint64_t *perr)
{
enum tevent_req_state state;
uint64_t err;
if (tevent_req_is_error(req, &state, &err)) {
*perr = err;
return -1;
}
return 0;
}
Parameters
[in]reqThe tevent request to get the error from.
[out]stateA pointer to store the tevent request error state.
[out]errorA pointer to store the error set by tevent_req_error().
Returns
True if the function could set error and state, false otherwise.
See also
tevent_req_error()

§ tevent_req_is_in_progress()

bool tevent_req_is_in_progress ( struct tevent_req *  req)

Check if the given request is still in progress.

It is typically used by sync wrapper functions.

Parameters
[in]reqThe request to poll.
Returns
The boolean form of "is in progress".

§ tevent_req_nomem()

bool tevent_req_nomem ( const void *  p,
struct tevent_req *  req 
)

Helper function for nomem check.

Convenience helper to easily check alloc failure within a callback implementing the next step of an async request.

Parameters
[in]pThe pointer to be checked.
[in]reqThe request being processed.
p = talloc(mem_ctx, bla);
if (tevent_req_nomem(p, req)) {
return;
}

§ tevent_req_notify_callback()

void tevent_req_notify_callback ( struct tevent_req *  req)

Call the notify callback of the given tevent request manually.

Parameters
[in]reqThe tevent request to call the notify function from.
See also
tevent_req_set_callback()

§ tevent_req_oom()

void tevent_req_oom ( struct tevent_req *  req)

Indicate out of memory to a request.

Parameters
[in]reqThe request being processed.

§ tevent_req_poll()

bool tevent_req_poll ( struct tevent_req *  req,
struct tevent_context *  ev 
)

Actively poll for the given request to finish.

This function is typically used by sync wrapper functions.

Parameters
[in]reqThe request to poll.
[in]evThe tevent_context to be used.
Returns
On success true is returned. If a critical error has happened in the tevent loop layer false is returned. This is not the return value of the given request!
Note
This should only be used if the given tevent context was created by the caller, to avoid event loop nesting.
req = tstream_writev_queue_send(mem_ctx,
ev_ctx,
tstream,
send_queue,
iov, 2);
ok = tevent_req_poll(req, tctx->ev);
rc = tstream_writev_queue_recv(req, &sys_errno);
TALLOC_FREE(req);

§ tevent_req_post()

struct tevent_req* tevent_req_post ( struct tevent_req *  req,
struct tevent_context *  ev 
)

Finish a request before the caller had the change to set the callback.

An implementation of an async request might find that it can either finish the request without waiting for an external event, or it can not even start the engine. To present the illusion of a callback to the user of the API, the implementation can call this helper function which triggers an immediate event. This way the caller can use the same calling conventions, independent of whether the request was actually deferred.

struct tevent_req *computation_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev)
{
struct tevent_req *req, *subreq;
struct computation_state *state;
req = tevent_req_create(mem_ctx, &state, struct computation_state);
if (req == NULL) {
return NULL;
}
subreq = subcomputation_send(state, ev);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, computation_done, req);
return req;
}
Parameters
[in]reqThe finished request.
[in]evThe tevent_context for the immediate event.
Returns
The given request will be returned.

§ tevent_req_print()

char* tevent_req_print ( TALLOC_CTX *  mem_ctx,
struct tevent_req *  req 
)

Print an tevent_req structure in debug messages.

This function should be used by callers of the async API.

Parameters
[in]mem_ctxThe memory context for the result.
[in]reqThe request to be printed.
Returns
Text representation of request.

§ tevent_req_received()

void tevent_req_received ( struct tevent_req *  req)

Use as the last action of a _recv() function.

This function destroys the attached private data.

Parameters
[in]reqThe finished request.

§ tevent_req_reset_endtime()

void tevent_req_reset_endtime ( struct tevent_req *  req)

Reset the timer set by tevent_req_set_endtime.

Parameters
[in]reqThe request to reset the timeout for

§ tevent_req_set_callback()

void tevent_req_set_callback ( struct tevent_req *  req,
tevent_req_fn  fn,
void *  pvt 
)

Set an async request callback.

See the documentation of tevent_req_post() for an example how this is supposed to be used.

Parameters
[in]reqThe async request to set the callback.
[in]fnThe callback function to set.
[in]pvtA pointer to private data to pass to the async request callback.

§ tevent_req_set_cancel_fn()

void tevent_req_set_cancel_fn ( struct tevent_req *  req,
tevent_req_cancel_fn  fn 
)

This function sets a cancel function for the given tevent request.

This function can be used to setup a cancel function for the given request. This will be triggered if the tevent_req_cancel() function was called on the given request.

Parameters
[in]reqThe request to use.
[in]fnA pointer to the cancel function.

§ tevent_req_set_cleanup_fn()

void tevent_req_set_cleanup_fn ( struct tevent_req *  req,
tevent_req_cleanup_fn  fn 
)

This function sets a cleanup function for the given tevent request.

This function can be used to setup a cleanup function for the given request. This will be triggered when the tevent_req_done() or tevent_req_error() function was called, before notifying the callers callback function, and also before scheduling the deferred trigger.

This might be useful if more than one tevent_req belong together and need to finish both requests at the same time.

The cleanup function is able to call tevent_req_done() or tevent_req_error() recursively, the cleanup function is only triggered the first time.

The cleanup function is also called by tevent_req_received() (possibly triggered from tevent_req_destructor()) before destroying the private data of the tevent_req.

Parameters
[in]reqThe request to use.
[in]fnA pointer to the cancel function.

§ tevent_req_set_endtime()

bool tevent_req_set_endtime ( struct tevent_req *  req,
struct tevent_context *  ev,
struct timeval  endtime 
)

Set a timeout for an async request.

Parameters
[in]reqThe request to set the timeout for.
[in]evThe event context to use for the timer.
[in]endtimeThe endtime of the request.
Returns
True if succeeded, false if not.

§ tevent_req_set_print_fn()

void tevent_req_set_print_fn ( struct tevent_req *  req,
tevent_req_print_fn  fn 
)

This function sets a print function for the given request.

This function can be used to setup a print function for the given request. This will be triggered if the tevent_req_print() function was called on the given request.

Parameters
[in]reqThe request to use.
[in]fnA pointer to the print function
Note
This function should only be used for debugging.

§ tevent_wakeup_recv()

bool tevent_wakeup_recv ( struct tevent_req *  req)

Check if the wakeup has been correctly executed.

This function needs to be called in the callback function set after calling tevent_wakeup_send().

Parameters
[in]reqThe tevent request to check.
Returns
True on success, false otherwise.
See also
tevent_wakeup_recv()

§ tevent_wakeup_send()

struct tevent_req* tevent_wakeup_send ( TALLOC_CTX *  mem_ctx,
struct tevent_context *  ev,
struct timeval  wakeup_time 
)

Create a tevent subrequest at a given time.

The idea is that always the same syntax for tevent requests.

Parameters
[in]mem_ctxThe talloc memory context to use.
[in]evThe event handle to setup the request.
[in]wakeup_timeThe time to wakeup and execute the request.
Returns
The new subrequest, NULL on error.

Example:

static void my_callback_wakeup_done(tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
bool ok;
ok = tevent_wakeup_recv(subreq);
TALLOC_FREE(subreq);
if (!ok) {
tevent_req_error(req, -1);
return;
}
...
}
subreq = tevent_wakeup_send(mem_ctx, ev, wakeup_time);
if (tevent_req_nomem(subreq, req)) {
return false;
}
tevent_set_callback(subreq, my_callback_wakeup_done, req);
See also
tevent_wakeup_recv()