>From 2dacf43a5af566f37f4805acee2d21bb09810853 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 11 Jan 2014 08:58:05 +0100 Subject: [PATCH 01/11] tevent: fix crash bug in tevent_queue_immediate_trigger() Assume we we have a queue with 2 entries (A and B with triggerA() and triggerB()). If triggerA() removes itself tevent_queue_entry_destructor() will be called for A, this schedules the immediate event to call triggerB(). If triggerA() then also removes B by an explicit of implizit talloc_free(), q->list is NULL, but the immediate event is still scheduled and can't be unscheduled. Signed-off-by: Stefan Metzmacher --- lib/tevent/tevent_queue.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c index 930319c..35742e5 100644 --- a/lib/tevent/tevent_queue.c +++ b/lib/tevent/tevent_queue.c @@ -141,6 +141,10 @@ static void tevent_queue_immediate_trigger(struct tevent_context *ev, return; } + if (!q->list) { + return; + } + q->list->triggered = true; q->list->trigger(q->list->req, q->list->private_data); } -- 1.7.9.5 >From 0bed3638ee1358c78bc700f9d2d838268126550d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 13 Dec 2013 11:59:43 +0100 Subject: [PATCH 02/11] tevent: Only build "std_fallback_to_poll" when epoll is around Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher --- lib/tevent/tevent_standard.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c index 785d68d..a050901 100644 --- a/lib/tevent/tevent_standard.c +++ b/lib/tevent/tevent_standard.c @@ -54,6 +54,7 @@ static const struct tevent_ops std_event_ops = { Move us to using poll instead. If we return false here, caller should abort(). */ +#ifdef HAVE_EPOLL static bool std_fallback_to_poll(struct tevent_context *ev, bool replay) { void *glue_ptr = talloc_parent(ev->ops); @@ -100,6 +101,7 @@ static bool std_fallback_to_poll(struct tevent_context *ev, bool replay) return true; } +#endif static int std_event_loop_once(struct tevent_context *ev, const char *location) { -- 1.7.9.5 >From 7d110c60b8707dfa8726cb0288b5b836454e1adf Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 13 Dec 2013 11:59:04 +0100 Subject: [PATCH 03/11] tevent: Add prototypes ... doxygen docs to be filled in :-) Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher --- lib/tevent/tevent.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h index 0705ff3..3f8e081 100644 --- a/lib/tevent/tevent.h +++ b/lib/tevent/tevent.h @@ -340,6 +340,10 @@ struct tevent_signal *_tevent_add_signal(struct tevent_context *ev, #handler, __location__) #endif +size_t tevent_num_signals(void); + +size_t tevent_sa_info_queue_count(void); + #ifdef DOXYGEN /** * @brief Pass a single time through the mainloop -- 1.7.9.5 >From c080d5936ba5e51a9b76bc6fa60bf2f997eca730 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jan 2014 10:01:56 +0100 Subject: [PATCH 04/11] tevent: add doxygen comments for tevent_num_signals() and tevent_sa_info_queue_count() Signed-off-by: Stefan Metzmacher --- lib/tevent/tevent.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h index 3f8e081..d7d4f19 100644 --- a/lib/tevent/tevent.h +++ b/lib/tevent/tevent.h @@ -319,6 +319,8 @@ void _tevent_schedule_immediate(struct tevent_immediate *im, * * @note To cancel a signal handler, call talloc_free() on the event returned * from this function. + * + * @see tevent_num_signals, tevent_sa_info_queue_count */ struct tevent_signal *tevent_add_signal(struct tevent_context *ev, TALLOC_CTX *mem_ctx, @@ -340,8 +342,29 @@ struct tevent_signal *_tevent_add_signal(struct tevent_context *ev, #handler, __location__) #endif +/** + * @brief the number of supported signals + * + * This returns value of the configure time TEVENT_NUM_SIGNALS constant. + * + * The 'signum' argument of tevent_add_signal() must be less than + * TEVENT_NUM_SIGNALS. + * + * @see tevent_add_signal + */ size_t tevent_num_signals(void); +/** + * @brief the number of pending realtime signals + * + * This returns value of TEVENT_SA_INFO_QUEUE_COUNT. + * + * The tevent internals remember the last TEVENT_SA_INFO_QUEUE_COUNT + * siginfo_t structures for SA_SIGINFO signals. If the system generates + * more some signals get lost. + * + * @see tevent_add_signal + */ size_t tevent_sa_info_queue_count(void); #ifdef DOXYGEN -- 1.7.9.5 >From 389901aa9b8b464c10bf0b83a3aa0bd8a5c55c83 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 27 Sep 2013 03:41:29 +0200 Subject: [PATCH 05/11] tevent: add/use tevent_req_destructor This makes sure we call tevent_req_received(req) on talloc_free() and cleanup things in a defined order. Note that some callers used their own destructor for their tevent_req instance, they'll just overwrite this, which is not intended, but works without problems. Signed-off-by: Stefan Metzmacher --- lib/tevent/tevent_req.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c index edb8550..30e91e2 100644 --- a/lib/tevent/tevent_req.c +++ b/lib/tevent/tevent_req.c @@ -51,6 +51,8 @@ char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req) return req->private_print(req, mem_ctx); } +static int tevent_req_destructor(struct tevent_req *req); + struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx, void *pdata, size_t data_size, @@ -86,10 +88,18 @@ struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx, req->data = data; + talloc_set_destructor(req, tevent_req_destructor); + *ppdata = data; return req; } +static int tevent_req_destructor(struct tevent_req *req) +{ + tevent_req_received(req); + return 0; +} + void _tevent_req_notify_callback(struct tevent_req *req, const char *location) { req->internal.finish_location = location; @@ -200,7 +210,8 @@ bool tevent_req_is_in_progress(struct tevent_req *req) void tevent_req_received(struct tevent_req *req) { - TALLOC_FREE(req->data); + talloc_set_destructor(req, NULL); + req->private_print = NULL; req->private_cancel = NULL; @@ -208,6 +219,8 @@ void tevent_req_received(struct tevent_req *req) TALLOC_FREE(req->internal.timer); req->internal.state = TEVENT_REQ_RECEIVED; + + TALLOC_FREE(req->data); } bool tevent_req_poll(struct tevent_req *req, -- 1.7.9.5 >From 7f5e7b1e7b58bd14e45067ecabc9397636e259af Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 27 Sep 2013 02:29:57 +0200 Subject: [PATCH 06/11] tevent: add tevent_req_set_cleanup_fn() Note that some callers used their own destructor for their tevent_req instance, they'll just overwrite this, which is not intended, but works without problems. The intended way is to specify a cleanup function and handle the TEVENT_REQ_RECEIVED state as destructor. Note that the TEVENT_REQ_RECEIVED cleanup event might be triggered by an explicit tevent_req_received() in the _recv() function. The TEVENT_REQ_RECEIVED event is only triggered once as tevent_req_received() will remove the destructor. So the difference compared to a custom destructor is that the struct tevent_req itself can continue to be there, while tevent_req_received() removed all internal state. Signed-off-by: Stefan Metzmacher --- lib/tevent/tevent.h | 35 +++++++++++++++++++++++++++++++++++ lib/tevent/tevent_internal.h | 12 ++++++++++++ lib/tevent/tevent_req.c | 22 ++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h index d7d4f19..44e66bc 100644 --- a/lib/tevent/tevent.h +++ b/lib/tevent/tevent.h @@ -934,6 +934,41 @@ bool _tevent_req_cancel(struct tevent_req *req, const char *location); _tevent_req_cancel(req, __location__) #endif +/** + * @brief A typedef for a cleanup function for a tevent request. + * + * @param[in] req The tevent request calling this function. + * + * @param[in] req_state The current tevent_req_state. + * + */ +typedef void (*tevent_req_cleanup_fn)(struct tevent_req *req, + enum tevent_req_state req_state); + +/** + * @brief This function sets a cleanup function for the given tevent request. + * + * This function can be used to setup a cleanup function for the given request. + * This will be triggered if the tevent_req_done() or tevent_req_error() + * function was called, before notifying the callers callback function, + * and also before scheduling the deferred trigger. + * + * This might be useful if more than one tevent_req belong together + * and need to finish both requests at the same time. + * + * The cleanup function is able to call tevent_req_done() or tevent_req_error() + * recursive, the cleanup function is only triggered the first time. + * + * The cleanup function is also called by tevent_req_received() + * (may triggered from tevent_req_destructor()) before destroying + * the private data of the tevent_req. + * + * @param[in] req The request to use. + * + * @param[in] fn A pointer to the cancel function. + */ +void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn); + #ifdef DOXYGEN /** * @brief Create an async tevent request. diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index df73288..d25dc05 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -74,6 +74,18 @@ struct tevent_req { tevent_req_cancel_fn private_cancel; /** + * @brief A function to cleanup the request + * + * The implementation might want to set a function + * that is called before the tevent_req_done() and tevent_req_error() + * trigger the callers callback function. + */ + struct { + tevent_req_cleanup_fn fn; + enum tevent_req_state state; + } private_cleanup; + + /** * @brief Internal state of the request * * Callers should only access this via functions and never directly. diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c index 30e91e2..c48fa58 100644 --- a/lib/tevent/tevent_req.c +++ b/lib/tevent/tevent_req.c @@ -124,6 +124,15 @@ static void tevent_req_finish(struct tevent_req *req, TALLOC_FREE(req->internal.timer); req->internal.state = state; + req->internal.finish_location = location; + + if (req->private_cleanup.fn != NULL) { + if (req->private_cleanup.state < req->internal.state) { + req->private_cleanup.state = req->internal.state; + req->private_cleanup.fn(req, req->internal.state); + } + } + _tevent_req_notify_callback(req, location); } @@ -220,6 +229,13 @@ void tevent_req_received(struct tevent_req *req) req->internal.state = TEVENT_REQ_RECEIVED; + if (req->private_cleanup.fn != NULL) { + if (req->private_cleanup.state < req->internal.state) { + req->private_cleanup.state = req->internal.state; + req->private_cleanup.fn(req, req->internal.state); + } + } + TALLOC_FREE(req->data); } @@ -315,3 +331,9 @@ bool _tevent_req_cancel(struct tevent_req *req, const char *location) return req->private_cancel(req); } + +void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn) +{ + req->private_cleanup.state = req->internal.state; + req->private_cleanup.fn = fn; +} -- 1.7.9.5 >From 62149cb684ce656ff6c9818db459e346e3a3dbe1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 27 Sep 2013 04:06:00 +0200 Subject: [PATCH 07/11] tevent: version 0.9.21 This fixes a the following bugs: - fix a crash bug in tevent_queue_immediate_trigger() - add missing tevent_num_signals() and tevent_sa_info_queue_count() prototypes including documentation. This adds the following new features: - tevent_req_set_cleanup_fn() Signed-off-by: Stefan Metzmacher --- lib/tevent/ABI/tevent-0.9.21.sigs | 88 +++++++++++++++++++++++++++++++++++++ lib/tevent/wscript | 2 +- 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 lib/tevent/ABI/tevent-0.9.21.sigs diff --git a/lib/tevent/ABI/tevent-0.9.21.sigs b/lib/tevent/ABI/tevent-0.9.21.sigs new file mode 100644 index 0000000..d8b9f4b --- /dev/null +++ b/lib/tevent/ABI/tevent-0.9.21.sigs @@ -0,0 +1,88 @@ +_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) +_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) +_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) +_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *) +_tevent_loop_once: int (struct tevent_context *, const char *) +_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *) +_tevent_loop_wait: int (struct tevent_context *, const char *) +_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *) +_tevent_req_callback_data: void *(struct tevent_req *) +_tevent_req_cancel: bool (struct tevent_req *, const char *) +_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *) +_tevent_req_data: void *(struct tevent_req *) +_tevent_req_done: void (struct tevent_req *, const char *) +_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *) +_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *) +_tevent_req_notify_callback: void (struct tevent_req *, const char *) +_tevent_req_oom: void (struct tevent_req *, const char *) +_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) +tevent_backend_list: const char **(TALLOC_CTX *) +tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *) +tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) +tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) +tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) +tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) +tevent_common_check_signal: int (struct tevent_context *) +tevent_common_context_destructor: int (struct tevent_context *) +tevent_common_fd_destructor: int (struct tevent_fd *) +tevent_common_fd_get_flags: uint16_t (struct tevent_fd *) +tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) +tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t) +tevent_common_loop_immediate: bool (struct tevent_context *) +tevent_common_loop_timer_delay: struct timeval (struct tevent_context *) +tevent_common_loop_wait: int (struct tevent_context *, const char *) +tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) +tevent_context_init: struct tevent_context *(TALLOC_CTX *) +tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) +tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) +tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...) +tevent_fd_get_flags: uint16_t (struct tevent_fd *) +tevent_fd_set_auto_close: void (struct tevent_fd *) +tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) +tevent_fd_set_flags: void (struct tevent_fd *, uint16_t) +tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *) +tevent_loop_allow_nesting: void (struct tevent_context *) +tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *) +tevent_num_signals: size_t (void) +tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) +tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) +tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) +tevent_queue_length: size_t (struct tevent_queue *) +tevent_queue_running: bool (struct tevent_queue *) +tevent_queue_start: void (struct tevent_queue *) +tevent_queue_stop: void (struct tevent_queue *) +tevent_queue_wait_recv: bool (struct tevent_req *) +tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *) +tevent_re_initialise: int (struct tevent_context *) +tevent_register_backend: bool (const char *, const struct tevent_ops *) +tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *) +tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *) +tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *) +tevent_req_is_in_progress: bool (struct tevent_req *) +tevent_req_poll: bool (struct tevent_req *, struct tevent_context *) +tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *) +tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *) +tevent_req_received: void (struct tevent_req *) +tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *) +tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn) +tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn) +tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval) +tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn) +tevent_sa_info_queue_count: size_t (void) +tevent_set_abort_fn: void (void (*)(const char *)) +tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *) +tevent_set_debug_stderr: int (struct tevent_context *) +tevent_set_default_backend: void (const char *) +tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *) +tevent_signal_support: bool (struct tevent_context *) +tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t) +tevent_timeval_compare: int (const struct timeval *, const struct timeval *) +tevent_timeval_current: struct timeval (void) +tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t) +tevent_timeval_is_zero: bool (const struct timeval *) +tevent_timeval_set: struct timeval (uint32_t, uint32_t) +tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *) +tevent_timeval_zero: struct timeval (void) +tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point) +tevent_wakeup_recv: bool (struct tevent_req *) +tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval) diff --git a/lib/tevent/wscript b/lib/tevent/wscript index 3fc87f5..bd19780 100755 --- a/lib/tevent/wscript +++ b/lib/tevent/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'tevent' -VERSION = '0.9.20' +VERSION = '0.9.21' blddir = 'bin' -- 1.7.9.5 >From 74f340e14c4dbaa5acc31032d79e70b0f64396d1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jan 2014 10:31:15 +0100 Subject: [PATCH 08/11] libcli/smb: make use of tevent_req_set_cleanup_fn() This is more better than a custom tevent_req destructor. Signed-off-by: Stefan Metzmacher --- libcli/smb/smbXcli_base.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 082b626..43dd994 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -785,7 +785,7 @@ void smbXcli_req_unset_pending(struct tevent_req *req) return; } - talloc_set_destructor(req, NULL); + tevent_req_set_cleanup_fn(req, NULL); if (num_pending == 1) { /* @@ -828,19 +828,25 @@ void smbXcli_req_unset_pending(struct tevent_req *req) return; } -static int smbXcli_req_destructor(struct tevent_req *req) +static void smbXcli_req_cleanup(struct tevent_req *req, + enum tevent_req_state req_state) { struct smbXcli_req_state *state = tevent_req_data(req, struct smbXcli_req_state); - /* - * Make sure we really remove it from - * the pending array on destruction. - */ - state->smb1.mid = 0; - smbXcli_req_unset_pending(req); - return 0; + switch (req_state) { + case TEVENT_REQ_RECEIVED: + /* + * Make sure we really remove it from + * the pending array on destruction. + */ + state->smb1.mid = 0; + smbXcli_req_unset_pending(req); + return; + default: + return; + } } static bool smb1cli_req_cancel(struct tevent_req *req); @@ -893,7 +899,7 @@ bool smbXcli_req_set_pending(struct tevent_req *req) } pending[num_pending] = req; conn->pending = pending; - talloc_set_destructor(req, smbXcli_req_destructor); + tevent_req_set_cleanup_fn(req, smbXcli_req_cleanup); tevent_req_set_cancel_fn(req, smbXcli_req_cancel); if (!smbXcli_conn_receive_next(conn)) { -- 1.7.9.5 >From e3d7f8eb2c34235d33847097452d96a0bba1db89 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jan 2014 10:31:15 +0100 Subject: [PATCH 09/11] s3:lib/fncall: make use of tevent_req_set_cleanup_fn() This is more better than a custom tevent_req destructor. Signed-off-by: Stefan Metzmacher --- source3/lib/fncall.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/source3/lib/fncall.c b/source3/lib/fncall.c index fb3d5c9..7f728ba 100644 --- a/source3/lib/fncall.c +++ b/source3/lib/fncall.c @@ -122,7 +122,8 @@ static int fncall_next_job_id(struct fncall_context *ctx) } static void fncall_unset_pending(struct tevent_req *req); -static int fncall_destructor(struct tevent_req *req); +static void fncall_cleanup(struct tevent_req *req, + enum tevent_req_state req_state); static bool fncall_set_pending(struct tevent_req *req, struct fncall_context *ctx, @@ -141,12 +142,12 @@ static bool fncall_set_pending(struct tevent_req *req, pending[num_pending] = req; num_pending += 1; ctx->pending = pending; - talloc_set_destructor(req, fncall_destructor); + tevent_req_set_cleanup_fn(req, fncall_cleanup); /* * Make sure that the orphaned array of fncall_state structs has * enough space. A job can change from pending to orphaned in - * fncall_destructor, and to fail in a talloc destructor should be + * fncall_cleanup, and to fail in a talloc destructor should be * avoided if possible. */ @@ -184,6 +185,8 @@ static void fncall_unset_pending(struct tevent_req *req) int num_pending = talloc_array_length(ctx->pending); int i; + tevent_req_set_cleanup_fn(req, NULL); + if (num_pending == 1) { TALLOC_FREE(ctx->fde); TALLOC_FREE(ctx->pending); @@ -205,16 +208,24 @@ static void fncall_unset_pending(struct tevent_req *req) num_pending - 1); } -static int fncall_destructor(struct tevent_req *req) +static void fncall_cleanup(struct tevent_req *req, + enum tevent_req_state req_state) { struct fncall_state *state = tevent_req_data( req, struct fncall_state); struct fncall_context *ctx = state->ctx; + switch (req_state) { + case TEVENT_REQ_RECEIVED: + break; + default: + return; + } + fncall_unset_pending(req); if (state->done) { - return 0; + return; } /* @@ -223,8 +234,6 @@ static int fncall_destructor(struct tevent_req *req) */ ctx->orphaned[ctx->num_orphaned] = talloc_move(ctx->orphaned, &state); ctx->num_orphaned += 1; - - return 0; } struct tevent_req *fncall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- 1.7.9.5 >From d20d5c90e41963800079438254ad6a59bcbd86aa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jan 2014 19:46:01 +0100 Subject: [PATCH 10/11] s3:lib/tldap: make use of tevent_req_defer_callback() In tldap_msg_received() we call tevent_req_error() for more than one request, if we do that we need to use tevent_req_defer_callback() otherwise we're likely to crash, as a triggered callback may invalidate our state. Signed-off-by: Stefan Metzmacher --- source3/lib/tldap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c index b094c2d..a566a91 100644 --- a/source3/lib/tldap.c +++ b/source3/lib/tldap.c @@ -650,6 +650,8 @@ static void tldap_msg_received(struct tevent_req *subreq) fail: while (talloc_array_length(ld->pending) > 0) { req = ld->pending[0]; + state = tevent_req_data(req, struct tldap_msg_state); + tevent_req_defer_callback(req, state->ev); talloc_set_destructor(req, NULL); tldap_msg_destructor(req); tevent_req_error(req, status); -- 1.7.9.5 >From c63def649e61ce4efd8aaf98cbad56ac8480885d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jan 2014 10:31:15 +0100 Subject: [PATCH 11/11] s3:lib/tldap: make use of tevent_req_set_cleanup_fn() This is more better than a custom tevent_req destructor. Signed-off-by: Stefan Metzmacher --- source3/lib/tldap.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c index a566a91..b15ee73 100644 --- a/source3/lib/tldap.c +++ b/source3/lib/tldap.c @@ -444,6 +444,8 @@ static void tldap_msg_unset_pending(struct tevent_req *req) int num_pending = talloc_array_length(ld->pending); int i; + tevent_req_set_cleanup_fn(req, NULL); + if (num_pending == 1) { TALLOC_FREE(ld->pending); return; @@ -479,10 +481,17 @@ static void tldap_msg_unset_pending(struct tevent_req *req) return; } -static int tldap_msg_destructor(struct tevent_req *req) +static void tldap_msg_cleanup(struct tevent_req *req, + enum tevent_req_state req_state) { - tldap_msg_unset_pending(req); - return 0; + switch (req_state) { + case TEVENT_REQ_USER_ERROR: + case TEVENT_REQ_RECEIVED: + tldap_msg_unset_pending(req); + return; + default: + return; + } } static bool tldap_msg_set_pending(struct tevent_req *req) @@ -504,7 +513,7 @@ static bool tldap_msg_set_pending(struct tevent_req *req) } pending[num_pending] = req; ld->pending = pending; - talloc_set_destructor(req, tldap_msg_destructor); + tevent_req_set_cleanup_fn(req, tldap_msg_cleanup); if (num_pending > 0) { return true; @@ -618,7 +627,6 @@ static void tldap_msg_received(struct tevent_req *subreq) state->inbuf = talloc_move(state, &inbuf); state->data = talloc_move(state, &data); - talloc_set_destructor(req, NULL); tldap_msg_unset_pending(req); num_pending = talloc_array_length(ld->pending); @@ -652,8 +660,6 @@ static void tldap_msg_received(struct tevent_req *subreq) req = ld->pending[0]; state = tevent_req_data(req, struct tldap_msg_state); tevent_req_defer_callback(req, state->ev); - talloc_set_destructor(req, NULL); - tldap_msg_destructor(req); tevent_req_error(req, status); } } -- 1.7.9.5