summaryrefslogtreecommitdiffstats
path: root/lib/tevent
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2013-09-27 02:29:57 +0200
committerStefan Metzmacher <metze@samba.org>2014-01-17 12:38:08 +0100
commit50b9f154d22f5c356e66bba341e9ee0292218cfd (patch)
tree3ead5cfe68d2dad847c8436e7bdd2c9840d78278 /lib/tevent
parent0ed93e099af833045d9d00b9a8faeb5b93b6ef2e (diff)
downloadsamba-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.h35
-rw-r--r--lib/tevent/tevent_internal.h12
-rw-r--r--lib/tevent/tevent_req.c30
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;
+}