summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/tevent/tevent.h42
-rw-r--r--lib/tevent/tevent_internal.h6
-rw-r--r--lib/tevent/tevent_req.c12
3 files changed, 60 insertions, 0 deletions
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 7f9f72a57a..7ad566c69e 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -1048,6 +1048,48 @@ struct tevent_req *tevent_req_post(struct tevent_req *req,
struct tevent_context *ev);
/**
+ * @brief 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()).
+ *
+ * @code
+ * 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]);
+ * }
+ * }
+ * @endcode
+ *
+ * @param[in] req The finished request.
+ *
+ * @param[in] ev The tevent_context for the immediate event.
+ *
+ * @return The given request will be returned.
+ */
+void tevent_req_defer_callback(struct tevent_req *req,
+ struct tevent_context *ev);
+
+/**
* @brief Check if the given request is still in progress.
*
* It is typically used by sync wrapper functions.
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 9227f90315..472beb5c94 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -142,6 +142,12 @@ struct tevent_req {
struct tevent_immediate *trigger;
/**
+ * @brief An event context which will be used to
+ * defer the _tevent_req_notify_callback().
+ */
+ struct tevent_context *defer_callback_ev;
+
+ /**
* @brief the timer event if tevent_req_set_endtime was used
*
*/
diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c
index 92697b7df9..d8d0c5f564 100644
--- a/lib/tevent/tevent_req.c
+++ b/lib/tevent/tevent_req.c
@@ -74,6 +74,7 @@ struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
talloc_free(req);
return NULL;
}
+ req->internal.defer_callback_ev = NULL;
data = talloc_zero_size(req, data_size);
if (data == NULL) {
@@ -91,6 +92,11 @@ struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
{
req->internal.finish_location = location;
+ if (req->internal.defer_callback_ev) {
+ (void)tevent_req_post(req, req->internal.defer_callback_ev);
+ req->internal.defer_callback_ev = NULL;
+ return;
+ }
if (req->async.fn != NULL) {
req->async.fn(req);
}
@@ -169,6 +175,12 @@ struct tevent_req *tevent_req_post(struct tevent_req *req,
return req;
}
+void tevent_req_defer_callback(struct tevent_req *req,
+ struct tevent_context *ev)
+{
+ req->internal.defer_callback_ev = ev;
+}
+
bool tevent_req_is_in_progress(struct tevent_req *req)
{
if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {