diff options
-rw-r--r-- | lib/tevent/tevent.h | 42 | ||||
-rw-r--r-- | lib/tevent/tevent_internal.h | 6 | ||||
-rw-r--r-- | lib/tevent/tevent_req.c | 12 |
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) { |