2 Unix SMB/CIFS implementation.
3 Infrastructure for async requests
4 Copyright (C) Volker Lendecke 2008
5 Copyright (C) Stefan Metzmacher 2009
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 #include "tevent_internal.h"
28 #include "tevent_util.h"
31 * @brief Print an tevent_req structure in debug messages
32 * @param[in] mem_ctx The memory context for the result
33 * @param[in] req The request to be printed
34 * @retval Text representation of req
38 char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
40 return talloc_asprintf(mem_ctx,
41 "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
42 " state[%s (%p)] timer[%p]",
43 req, req->internal.location,
45 (unsigned long long)req->internal.error,
46 (unsigned long long)req->internal.error,
47 talloc_get_name(req->private_state),
54 * @brief Create an async request
55 * @param[in] mem_ctx The memory context for the result
56 * @param[in] ev The event context this async request will be driven by
57 * @retval A new async request
59 * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
62 struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
68 struct tevent_req *req;
69 void **ppstate = (void **)pstate;
72 req = talloc_zero(mem_ctx, struct tevent_req);
76 req->internal.private_type = type;
77 req->internal.location = location;
78 req->internal.state = TEVENT_REQ_IN_PROGRESS;
80 state = talloc_size(req, state_size);
85 talloc_set_name_const(state, type);
87 req->private_state = state;
93 static void tevent_req_finish(struct tevent_req *req, enum tevent_req_state state)
95 req->internal.state = state;
96 if (req->async.fn != NULL) {
102 * @brief An async request has successfully finished
103 * @param[in] req The finished request
105 * async_req_done is to be used by implementors of async requests. When a
106 * request is successfully finished, this function calls the user's completion
110 void tevent_req_done(struct tevent_req *req)
112 tevent_req_finish(req, TEVENT_REQ_DONE);
116 * @brief An async request has seen an error
117 * @param[in] req The request with an error
118 * @param[in] error The error code
120 * tevent_req_done is to be used by implementors of async requests. When a
121 * request can not successfully completed, the implementation should call this
122 * function with the appropriate status code.
124 * If error is 0 the function returns false and does nothing more.
126 * Call pattern would be
128 * int error = first_function();
129 * if (tevent_req_error(req, error)) {
133 * error = second_function();
134 * if (tevent_req_error(req, error)) {
138 * tevent_req_done(req);
143 bool tevent_req_error(struct tevent_req *req, uint64_t error)
149 req->internal.error = error;
150 tevent_req_finish(req, TEVENT_REQ_USER_ERROR);
155 * @brief Helper function for nomem check
156 * @param[in] p The pointer to be checked
157 * @param[in] req The request being processed
159 * Convenience helper to easily check alloc failure within a callback
160 * implementing the next step of an async request.
162 * Call pattern would be
164 * p = talloc(mem_ctx, bla);
165 * if (tevent_req_nomem(p, req)) {
171 bool tevent_req_nomem(const void *p, struct tevent_req *req)
176 tevent_req_finish(req, TEVENT_REQ_NO_MEMORY);
181 * @brief Timed event callback
182 * @param[in] ev Event context
183 * @param[in] te The timed event
184 * @param[in] now zero time
185 * @param[in] priv The async request to be finished
187 static void tevent_req_trigger(struct tevent_context *ev,
188 struct tevent_timer *te,
192 struct tevent_req *req = talloc_get_type(private_data,
195 talloc_free(req->internal.trigger);
196 req->internal.trigger = NULL;
198 tevent_req_finish(req, req->internal.state);
202 * @brief Finish a request before the caller had the change to set the callback
203 * @param[in] req The finished request
204 * @param[in] ev The tevent_context for the timed event
205 * @retval On success req will be returned,
206 * on failure req will be destroyed
208 * An implementation of an async request might find that it can either finish
209 * the request without waiting for an external event, or it can't even start
210 * the engine. To present the illusion of a callback to the user of the API,
211 * the implementation can call this helper function which triggers an
212 * immediate timed event. This way the caller can use the same calling
213 * conventions, independent of whether the request was actually deferred.
216 struct tevent_req *tevent_req_post(struct tevent_req *req,
217 struct tevent_context *ev)
219 req->internal.trigger = tevent_add_timer(ev, req, tevent_timeval_zero(),
220 tevent_req_trigger, req);
221 if (!req->internal.trigger) {
229 bool tevent_req_is_in_progress(struct tevent_req *req)
231 if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
238 bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
241 if (req->internal.state == TEVENT_REQ_DONE) {
244 if (req->internal.state == TEVENT_REQ_USER_ERROR) {
245 *error = req->internal.error;
247 *state = req->internal.state;
251 static void tevent_req_timedout(struct tevent_context *ev,
252 struct tevent_timer *te,
256 struct tevent_req *req = talloc_get_type(private_data,
259 talloc_free(req->internal.timer);
260 req->internal.timer = NULL;
262 tevent_req_finish(req, TEVENT_REQ_TIMED_OUT);
265 bool tevent_req_set_endtime(struct tevent_req *req,
266 struct tevent_context *ev,
267 struct timeval endtime)
269 talloc_free(req->internal.timer);
271 req->internal.timer = tevent_add_timer(ev, req, endtime,
274 if (tevent_req_nomem(req->internal.timer, req)) {