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"
30 char *tevent_req_default_print(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
)
32 return talloc_asprintf(mem_ctx
,
33 "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
34 " state[%s (%p)] timer[%p] finish[%s]",
35 req
, req
->internal
.create_location
,
37 (unsigned long long)req
->internal
.error
,
38 (unsigned long long)req
->internal
.error
,
39 req
->internal
.private_type
,
42 req
->internal
.finish_location
46 char *tevent_req_print(TALLOC_CTX
*mem_ctx
, struct tevent_req
*req
)
49 return talloc_strdup(mem_ctx
, "tevent_req[NULL]");
52 if (!req
->private_print
) {
53 return tevent_req_default_print(req
, mem_ctx
);
56 return req
->private_print(req
, mem_ctx
);
59 static int tevent_req_destructor(struct tevent_req
*req
);
61 struct tevent_req
*_tevent_req_create(TALLOC_CTX
*mem_ctx
,
67 struct tevent_req
*req
;
68 struct tevent_req
*parent
;
69 void **ppdata
= (void **)pdata
;
73 payload
= sizeof(struct tevent_immediate
) + data_size
;
74 if (payload
< sizeof(struct tevent_immediate
)) {
79 req
= talloc_pooled_object(
80 mem_ctx
, struct tevent_req
, 2,
81 sizeof(struct tevent_immediate
) + data_size
);
86 *req
= (struct tevent_req
) {
89 .create_location
= location
,
90 .state
= TEVENT_REQ_IN_PROGRESS
,
91 .trigger
= tevent_create_immediate(req
),
95 data
= talloc_zero_size(req
, data_size
);
98 * No need to check for req->internal.trigger!=NULL or
99 * data!=NULL, this can't fail: talloc_pooled_object has
100 * already allocated sufficient memory.
103 talloc_set_name_const(data
, type
);
107 talloc_set_destructor(req
, tevent_req_destructor
);
109 parent
= talloc_get_type(talloc_parent(mem_ctx
), struct tevent_req
);
110 if ((parent
!= NULL
) && (parent
->internal
.profile
!= NULL
)) {
111 bool ok
= tevent_req_set_profile(req
);
117 req
->internal
.profile
->parent
= parent
->internal
.profile
;
118 DLIST_ADD_END(parent
->internal
.profile
->subprofiles
,
119 req
->internal
.profile
);
126 static int tevent_req_destructor(struct tevent_req
*req
)
128 tevent_req_received(req
);
132 void _tevent_req_notify_callback(struct tevent_req
*req
, const char *location
)
134 req
->internal
.finish_location
= location
;
135 if (req
->internal
.defer_callback_ev
) {
136 (void)tevent_req_post(req
, req
->internal
.defer_callback_ev
);
137 req
->internal
.defer_callback_ev
= NULL
;
140 if (req
->async
.fn
!= NULL
) {
145 static void tevent_req_cleanup(struct tevent_req
*req
)
147 if (req
->private_cleanup
.fn
== NULL
) {
151 if (req
->private_cleanup
.state
>= req
->internal
.state
) {
153 * Don't call the cleanup_function multiple times for the same
159 req
->private_cleanup
.state
= req
->internal
.state
;
160 req
->private_cleanup
.fn(req
, req
->internal
.state
);
163 static void tevent_req_finish(struct tevent_req
*req
,
164 enum tevent_req_state state
,
165 const char *location
)
167 struct tevent_req_profile
*p
;
169 * make sure we do not timeout after
170 * the request was already finished
172 TALLOC_FREE(req
->internal
.timer
);
174 req
->internal
.state
= state
;
175 req
->internal
.finish_location
= location
;
177 tevent_req_cleanup(req
);
179 p
= req
->internal
.profile
;
182 p
->stop_location
= location
;
183 p
->stop_time
= tevent_timeval_current();
185 p
->user_error
= req
->internal
.error
;
187 if (p
->parent
!= NULL
) {
188 talloc_steal(p
->parent
, p
);
189 req
->internal
.profile
= NULL
;
193 _tevent_req_notify_callback(req
, location
);
196 void _tevent_req_done(struct tevent_req
*req
,
197 const char *location
)
199 tevent_req_finish(req
, TEVENT_REQ_DONE
, location
);
202 bool _tevent_req_error(struct tevent_req
*req
,
204 const char *location
)
210 req
->internal
.error
= error
;
211 tevent_req_finish(req
, TEVENT_REQ_USER_ERROR
, location
);
215 void _tevent_req_oom(struct tevent_req
*req
, const char *location
)
217 tevent_req_finish(req
, TEVENT_REQ_NO_MEMORY
, location
);
220 bool _tevent_req_nomem(const void *p
,
221 struct tevent_req
*req
,
222 const char *location
)
227 _tevent_req_oom(req
, location
);
234 * @brief Immediate event callback.
236 * @param[in] ev The event context to use.
238 * @param[in] im The immediate event.
240 * @param[in] priv The async request to be finished.
242 static void tevent_req_trigger(struct tevent_context
*ev
,
243 struct tevent_immediate
*im
,
246 struct tevent_req
*req
=
247 talloc_get_type_abort(private_data
,
250 tevent_req_finish(req
, req
->internal
.state
,
251 req
->internal
.finish_location
);
254 struct tevent_req
*tevent_req_post(struct tevent_req
*req
,
255 struct tevent_context
*ev
)
257 tevent_schedule_immediate(req
->internal
.trigger
,
258 ev
, tevent_req_trigger
, req
);
262 void tevent_req_defer_callback(struct tevent_req
*req
,
263 struct tevent_context
*ev
)
265 req
->internal
.defer_callback_ev
= ev
;
268 bool tevent_req_is_in_progress(struct tevent_req
*req
)
270 if (req
->internal
.state
== TEVENT_REQ_IN_PROGRESS
) {
277 void tevent_req_received(struct tevent_req
*req
)
279 talloc_set_destructor(req
, NULL
);
281 req
->private_print
= NULL
;
282 req
->private_cancel
= NULL
;
284 TALLOC_FREE(req
->internal
.trigger
);
285 TALLOC_FREE(req
->internal
.timer
);
287 req
->internal
.state
= TEVENT_REQ_RECEIVED
;
289 tevent_req_cleanup(req
);
291 TALLOC_FREE(req
->data
);
294 bool tevent_req_poll(struct tevent_req
*req
,
295 struct tevent_context
*ev
)
297 while (tevent_req_is_in_progress(req
)) {
300 ret
= tevent_loop_once(ev
);
309 bool tevent_req_is_error(struct tevent_req
*req
, enum tevent_req_state
*state
,
312 if (req
->internal
.state
== TEVENT_REQ_DONE
) {
315 if (req
->internal
.state
== TEVENT_REQ_USER_ERROR
) {
316 *error
= req
->internal
.error
;
318 *state
= req
->internal
.state
;
322 static void tevent_req_timedout(struct tevent_context
*ev
,
323 struct tevent_timer
*te
,
327 struct tevent_req
*req
=
328 talloc_get_type_abort(private_data
,
331 TALLOC_FREE(req
->internal
.timer
);
333 tevent_req_finish(req
, TEVENT_REQ_TIMED_OUT
, __FUNCTION__
);
336 bool tevent_req_set_endtime(struct tevent_req
*req
,
337 struct tevent_context
*ev
,
338 struct timeval endtime
)
340 TALLOC_FREE(req
->internal
.timer
);
342 req
->internal
.timer
= tevent_add_timer(ev
, req
, endtime
,
345 if (tevent_req_nomem(req
->internal
.timer
, req
)) {
352 void tevent_req_reset_endtime(struct tevent_req
*req
)
354 TALLOC_FREE(req
->internal
.timer
);
357 void tevent_req_set_callback(struct tevent_req
*req
, tevent_req_fn fn
, void *pvt
)
360 req
->async
.private_data
= pvt
;
363 void *_tevent_req_callback_data(struct tevent_req
*req
)
365 return req
->async
.private_data
;
368 void *_tevent_req_data(struct tevent_req
*req
)
373 void tevent_req_set_print_fn(struct tevent_req
*req
, tevent_req_print_fn fn
)
375 req
->private_print
= fn
;
378 void tevent_req_set_cancel_fn(struct tevent_req
*req
, tevent_req_cancel_fn fn
)
380 req
->private_cancel
= fn
;
383 bool _tevent_req_cancel(struct tevent_req
*req
, const char *location
)
385 if (req
->private_cancel
== NULL
) {
389 return req
->private_cancel(req
);
392 void tevent_req_set_cleanup_fn(struct tevent_req
*req
, tevent_req_cleanup_fn fn
)
394 req
->private_cleanup
.state
= req
->internal
.state
;
395 req
->private_cleanup
.fn
= fn
;
398 static int tevent_req_profile_destructor(struct tevent_req_profile
*p
);
400 bool tevent_req_set_profile(struct tevent_req
*req
)
402 struct tevent_req_profile
*p
;
404 if (req
->internal
.profile
!= NULL
) {
405 tevent_req_error(req
, EINVAL
);
409 p
= tevent_req_profile_create(req
);
411 if (tevent_req_nomem(p
, req
)) {
415 p
->req_name
= talloc_get_name(req
->data
);
416 p
->start_location
= req
->internal
.create_location
;
417 p
->start_time
= tevent_timeval_current();
419 req
->internal
.profile
= p
;
424 static int tevent_req_profile_destructor(struct tevent_req_profile
*p
)
426 if (p
->parent
!= NULL
) {
427 DLIST_REMOVE(p
->parent
->subprofiles
, p
);
431 while (p
->subprofiles
!= NULL
) {
432 p
->subprofiles
->parent
= NULL
;
433 DLIST_REMOVE(p
->subprofiles
, p
->subprofiles
);
439 struct tevent_req_profile
*tevent_req_move_profile(struct tevent_req
*req
,
442 return talloc_move(mem_ctx
, &req
->internal
.profile
);
445 const struct tevent_req_profile
*tevent_req_get_profile(
446 struct tevent_req
*req
)
448 return req
->internal
.profile
;
451 void tevent_req_profile_get_name(const struct tevent_req_profile
*profile
,
452 const char **req_name
)
454 if (req_name
!= NULL
) {
455 *req_name
= profile
->req_name
;
459 void tevent_req_profile_get_start(const struct tevent_req_profile
*profile
,
460 const char **start_location
,
461 struct timeval
*start_time
)
463 if (start_location
!= NULL
) {
464 *start_location
= profile
->start_location
;
466 if (start_time
!= NULL
) {
467 *start_time
= profile
->start_time
;
471 void tevent_req_profile_get_stop(const struct tevent_req_profile
*profile
,
472 const char **stop_location
,
473 struct timeval
*stop_time
)
475 if (stop_location
!= NULL
) {
476 *stop_location
= profile
->stop_location
;
478 if (stop_time
!= NULL
) {
479 *stop_time
= profile
->stop_time
;
483 void tevent_req_profile_get_status(const struct tevent_req_profile
*profile
,
485 enum tevent_req_state
*state
,
486 uint64_t *user_error
)
492 *state
= profile
->state
;
494 if (user_error
!= NULL
) {
495 *user_error
= profile
->user_error
;
499 const struct tevent_req_profile
*tevent_req_profile_get_subprofiles(
500 const struct tevent_req_profile
*profile
)
502 return profile
->subprofiles
;
505 const struct tevent_req_profile
*tevent_req_profile_next(
506 const struct tevent_req_profile
*profile
)
508 return profile
->next
;
511 struct tevent_req_profile
*tevent_req_profile_create(TALLOC_CTX
*mem_ctx
)
513 struct tevent_req_profile
*result
;
515 result
= talloc_zero(mem_ctx
, struct tevent_req_profile
);
516 if (result
== NULL
) {
519 talloc_set_destructor(result
, tevent_req_profile_destructor
);
524 bool tevent_req_profile_set_name(struct tevent_req_profile
*profile
,
525 const char *req_name
)
527 profile
->req_name
= talloc_strdup(profile
, req_name
);
528 return (profile
->req_name
!= NULL
);
531 bool tevent_req_profile_set_start(struct tevent_req_profile
*profile
,
532 const char *start_location
,
533 struct timeval start_time
)
535 profile
->start_time
= start_time
;
537 profile
->start_location
= talloc_strdup(profile
, start_location
);
538 return (profile
->start_location
!= NULL
);
541 bool tevent_req_profile_set_stop(struct tevent_req_profile
*profile
,
542 const char *stop_location
,
543 struct timeval stop_time
)
545 profile
->stop_time
= stop_time
;
547 profile
->stop_location
= talloc_strdup(profile
, stop_location
);
548 return (profile
->stop_location
!= NULL
);
551 void tevent_req_profile_set_status(struct tevent_req_profile
*profile
,
553 enum tevent_req_state state
,
557 profile
->state
= state
;
558 profile
->user_error
= user_error
;
561 void tevent_req_profile_append_sub(struct tevent_req_profile
*parent_profile
,
562 struct tevent_req_profile
**sub_profile
)
564 struct tevent_req_profile
*sub
;
566 sub
= talloc_move(parent_profile
, sub_profile
);
568 sub
->parent
= parent_profile
;
569 DLIST_ADD_END(parent_profile
->subprofiles
, sub
);