2 Unix SMB/CIFS implementation.
3 Infrastructure for async requests
4 Copyright (C) Volker Lendecke 2008
5 Copyright (C) Stefan Metzmacher 2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "tevent_internal.h"
24 #include "tevent_util.h"
27 * @brief Print an tevent_req structure in debug messages
28 * @param[in] mem_ctx The memory context for the result
29 * @param[in] req The request to be printed
30 * @retval Text representation of req
34 char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
36 return talloc_asprintf(mem_ctx,
37 "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
38 " state[%s (%p)] timer[%p]",
39 req, req->internal.location,
41 (unsigned long long)req->internal.error,
42 (unsigned long long)req->internal.error,
43 talloc_get_name(req->private_state),
50 * @brief Create an async request
51 * @param[in] mem_ctx The memory context for the result
52 * @param[in] ev The event context this async request will be driven by
53 * @retval A new async request
55 * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
58 struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
64 struct tevent_req *req;
65 void **ppstate = (void **)pstate;
68 req = talloc_zero(mem_ctx, struct tevent_req);
72 req->internal.private_type = type;
73 req->internal.location = location;
74 req->internal.state = TEVENT_REQ_IN_PROGRESS;
76 state = talloc_size(req, state_size);
81 talloc_set_name_const(state, type);
83 req->private_state = state;
89 static void tevent_req_finish(struct tevent_req *req, enum tevent_req_state state)
91 req->internal.state = state;
92 if (req->async.fn != NULL) {
98 * @brief An async request has successfully finished
99 * @param[in] req The finished request
101 * async_req_done is to be used by implementors of async requests. When a
102 * request is successfully finished, this function calls the user's completion
106 void tevent_req_done(struct tevent_req *req)
108 tevent_req_finish(req, TEVENT_REQ_DONE);
112 * @brief An async request has seen an error
113 * @param[in] req The request with an error
114 * @param[in] error The error code
116 * tevent_req_done is to be used by implementors of async requests. When a
117 * request can not successfully completed, the implementation should call this
118 * function with the appropriate status code.
120 * If error is 0 the function returns false and does nothing more.
122 * Call pattern would be
124 * int error = first_function();
125 * if (tevent_req_error(req, error)) {
129 * error = second_function();
130 * if (tevent_req_error(req, error)) {
134 * tevent_req_done(req);
139 bool tevent_req_error(struct tevent_req *req, uint64_t error)
145 req->internal.error = error;
146 tevent_req_finish(req, TEVENT_REQ_USER_ERROR);
151 * @brief Helper function for nomem check
152 * @param[in] p The pointer to be checked
153 * @param[in] req The request being processed
155 * Convenience helper to easily check alloc failure within a callback
156 * implementing the next step of an async request.
158 * Call pattern would be
160 * p = talloc(mem_ctx, bla);
161 * if (tevent_req_nomem(p, req)) {
167 bool tevent_req_nomem(const void *p, struct tevent_req *req)
172 tevent_req_finish(req, TEVENT_REQ_NO_MEMORY);
177 * @brief Timed event callback
178 * @param[in] ev Event context
179 * @param[in] te The timed event
180 * @param[in] now zero time
181 * @param[in] priv The async request to be finished
183 static void tevent_req_trigger(struct tevent_context *ev,
184 struct tevent_timer *te,
188 struct tevent_req *req = talloc_get_type(private_data,
191 talloc_free(req->internal.trigger);
192 req->internal.trigger = NULL;
194 tevent_req_finish(req, req->internal.state);
198 * @brief Finish a request before the caller had the change to set the callback
199 * @param[in] req The finished request
200 * @param[in] ev The tevent_context for the timed event
201 * @retval On success req will be returned,
202 * on failure req will be destroyed
204 * An implementation of an async request might find that it can either finish
205 * the request without waiting for an external event, or it can't even start
206 * the engine. To present the illusion of a callback to the user of the API,
207 * the implementation can call this helper function which triggers an
208 * immediate timed event. This way the caller can use the same calling
209 * conventions, independent of whether the request was actually deferred.
212 struct tevent_req *tevent_req_post(struct tevent_req *req,
213 struct tevent_context *ev)
215 req->internal.trigger = tevent_add_timer(ev, req, ev_timeval_zero(),
216 tevent_req_trigger, req);
217 if (!req->internal.trigger) {
225 bool tevent_req_is_in_progress(struct tevent_req *req)
227 if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
234 bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
237 if (req->internal.state == TEVENT_REQ_DONE) {
240 if (req->internal.state == TEVENT_REQ_USER_ERROR) {
241 *error = req->internal.error;
243 *state = req->internal.state;
247 static void tevent_req_timedout(struct tevent_context *ev,
248 struct tevent_timer *te,
252 struct tevent_req *req = talloc_get_type(private_data,
255 talloc_free(req->internal.timer);
256 req->internal.timer = NULL;
258 tevent_req_finish(req, TEVENT_REQ_TIMED_OUT);
261 bool tevent_req_set_timeout(struct tevent_req *req,
262 struct tevent_context *ev,
263 struct timeval endtime)
265 talloc_free(req->internal.timer);
267 req->internal.timer = tevent_add_timer(ev, req, endtime,
270 if (tevent_req_nomem(req->internal.timer, req)) {