diff options
author | Stefan Metzmacher <metze@samba.org> | 2013-09-27 02:29:57 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2014-01-17 12:38:08 +0100 |
commit | 50b9f154d22f5c356e66bba341e9ee0292218cfd (patch) | |
tree | 3ead5cfe68d2dad847c8436e7bdd2c9840d78278 /lib/tevent | |
parent | 0ed93e099af833045d9d00b9a8faeb5b93b6ef2e (diff) | |
download | samba-50b9f154d22f5c356e66bba341e9ee0292218cfd.tar.gz samba-50b9f154d22f5c356e66bba341e9ee0292218cfd.tar.xz samba-50b9f154d22f5c356e66bba341e9ee0292218cfd.zip |
tevent: add tevent_req_set_cleanup_fn()
Note that some callers used their own destructor for their
tevent_req instance, they'll just overwrite this,
which is not intended, but works without problems.
The intended way is to specify a cleanup function
and handle the TEVENT_REQ_RECEIVED state as destructor.
Note that the TEVENT_REQ_RECEIVED cleanup event might
be triggered by an explicit tevent_req_received()
in the _recv() function. The TEVENT_REQ_RECEIVED event
is only triggered once as tevent_req_received()
will remove the destructor.
So the difference compared to a custom destructor
is that the struct tevent_req itself can continue
to be there, while tevent_req_received() removed
all internal state.
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
Diffstat (limited to 'lib/tevent')
-rw-r--r-- | lib/tevent/tevent.h | 35 | ||||
-rw-r--r-- | lib/tevent/tevent_internal.h | 12 | ||||
-rw-r--r-- | lib/tevent/tevent_req.c | 30 |
3 files changed, 77 insertions, 0 deletions
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h index d7d4f19eff..c54cbe2133 100644 --- a/lib/tevent/tevent.h +++ b/lib/tevent/tevent.h @@ -934,6 +934,41 @@ bool _tevent_req_cancel(struct tevent_req *req, const char *location); _tevent_req_cancel(req, __location__) #endif +/** + * @brief A typedef for a cleanup function for a tevent request. + * + * @param[in] req The tevent request calling this function. + * + * @param[in] req_state The current tevent_req_state. + * + */ +typedef void (*tevent_req_cleanup_fn)(struct tevent_req *req, + enum tevent_req_state req_state); + +/** + * @brief 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. + * + * @param[in] req The request to use. + * + * @param[in] fn A pointer to the cancel function. + */ +void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn); + #ifdef DOXYGEN /** * @brief Create an async tevent request. diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index df7328864d..d25dc050e3 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -74,6 +74,18 @@ struct tevent_req { tevent_req_cancel_fn private_cancel; /** + * @brief A function to cleanup the request + * + * The implementation might want to set a function + * that is called before the tevent_req_done() and tevent_req_error() + * trigger the callers callback function. + */ + struct { + tevent_req_cleanup_fn fn; + enum tevent_req_state state; + } private_cleanup; + + /** * @brief Internal state of the request * * Callers should only access this via functions and never directly. diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c index 30e91e2526..c86fb68f80 100644 --- a/lib/tevent/tevent_req.c +++ b/lib/tevent/tevent_req.c @@ -113,6 +113,24 @@ void _tevent_req_notify_callback(struct tevent_req *req, const char *location) } } +static void tevent_req_cleanup(struct tevent_req *req) +{ + if (req->private_cleanup.fn == NULL) { + return; + } + + if (req->private_cleanup.state >= req->internal.state) { + /* + * Don't call the cleanup_function multiple times for the same + * state recursively + */ + return; + } + + req->private_cleanup.state = req->internal.state; + req->private_cleanup.fn(req, req->internal.state); +} + static void tevent_req_finish(struct tevent_req *req, enum tevent_req_state state, const char *location) @@ -124,6 +142,10 @@ static void tevent_req_finish(struct tevent_req *req, TALLOC_FREE(req->internal.timer); req->internal.state = state; + req->internal.finish_location = location; + + tevent_req_cleanup(req); + _tevent_req_notify_callback(req, location); } @@ -220,6 +242,8 @@ void tevent_req_received(struct tevent_req *req) req->internal.state = TEVENT_REQ_RECEIVED; + tevent_req_cleanup(req); + TALLOC_FREE(req->data); } @@ -315,3 +339,9 @@ bool _tevent_req_cancel(struct tevent_req *req, const char *location) return req->private_cancel(req); } + +void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn) +{ + req->private_cleanup.state = req->internal.state; + req->private_cleanup.fn = fn; +} |