From: Stefan Metzmacher Date: Tue, 22 Jul 2014 11:01:01 +0000 (+0200) Subject: tevent: split out tevent_common_invoke_signal_handler() X-Git-Tag: tevent-0.9.37~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ddab21987d3edb17333a5759bd7bcbb7b5126b53;p=thirdparty%2Fsamba.git tevent: split out tevent_common_invoke_signal_handler() As side effect this avoids tricks with tevent_se_exists_destructor() to figure out if the event handler removed itself. We'll undo the 0.9.36 ABI change on the 0.9.37 release at the end of this patchset. Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme --- diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs index 8a9d1a6ba10..230f6b9f26b 100644 --- a/lib/tevent/ABI/tevent-0.9.36.sigs +++ b/lib/tevent/ABI/tevent-0.9.36.sigs @@ -32,6 +32,7 @@ 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_have_events: bool (struct tevent_context *) +tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *) 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 *) diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index 7e15a59d3fb..f36cd219f68 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -216,6 +216,8 @@ struct tevent_immediate { struct tevent_signal { struct tevent_signal *prev, *next; struct tevent_context *event_ctx; + bool busy; + bool destroyed; int signum; int sa_flags; tevent_signal_handler_t handler; @@ -378,6 +380,9 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, const char *location); int tevent_common_check_signal(struct tevent_context *ev); void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se); +int tevent_common_invoke_signal_handler(struct tevent_signal *se, + int signum, int count, void *siginfo, + bool *removed); bool tevent_standard_init(void); bool tevent_poll_init(void); diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c index ef230243316..a787f97b964 100644 --- a/lib/tevent/tevent_signal.c +++ b/lib/tevent/tevent_signal.c @@ -184,6 +184,12 @@ static int tevent_common_signal_list_destructor(struct tevent_common_signal_list */ static int tevent_signal_destructor(struct tevent_signal *se) { + if (se->destroyed) { + tevent_common_check_double_free(se, "tevent_signal double free"); + goto done; + } + se->destroyed = true; + TALLOC_FREE(se->additional_data); if (se->event_ctx != NULL) { @@ -205,6 +211,12 @@ static int tevent_signal_destructor(struct tevent_signal *se) #endif } + se->event_ctx = NULL; +done: + if (se->busy) { + return -1; + } + return 0; } @@ -322,13 +334,42 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, return se; } -struct tevent_se_exists { - struct tevent_se_exists **myself; -}; - -static int tevent_se_exists_destructor(struct tevent_se_exists *s) +int tevent_common_invoke_signal_handler(struct tevent_signal *se, + int signum, int count, void *siginfo, + bool *removed) { - *s->myself = NULL; + bool remove = false; + + if (removed != NULL) { + *removed = false; + } + + if (se->event_ctx == NULL) { + return 0; + } + + se->busy = true; + se->handler(se->event_ctx, se, signum, count, siginfo, se->private_data); + se->busy = false; + +#ifdef SA_RESETHAND + if (se->sa_flags & SA_RESETHAND) { + remove = true; + } +#endif + + if (se->destroyed) { + talloc_set_destructor(se, NULL); + remove = true; + } + + if (remove) { + TALLOC_FREE(se); + if (removed != NULL) { + *removed = true; + } + } + return 0; } @@ -348,6 +389,7 @@ int tevent_common_check_signal(struct tevent_context *ev) struct tevent_common_signal_list *sl, *next; struct tevent_sigcounter counter = sig_state->signal_count[i]; uint32_t count = tevent_sig_count(counter); + int ret; #ifdef SA_SIGINFO /* Ensure we null out any stored siginfo_t entries * after processing for debugging purposes. */ @@ -359,25 +401,9 @@ int tevent_common_check_signal(struct tevent_context *ev) } for (sl=sig_state->sig_handlers[i];sl;sl=next) { struct tevent_signal *se = sl->se; - struct tevent_se_exists *exists; next = sl->next; - /* - * We have to be careful to not touch "se" - * after it was deleted in its handler. Thus - * we allocate a child whose destructor will - * tell by nulling out itself that its parent - * is gone. - */ - exists = talloc(se, struct tevent_se_exists); - if (exists == NULL) { - continue; - } - exists->myself = &exists; - talloc_set_destructor( - exists, tevent_se_exists_destructor); - #ifdef SA_SIGINFO if (se->sa_flags & SA_SIGINFO) { uint32_t j; @@ -391,29 +417,28 @@ int tevent_common_check_signal(struct tevent_context *ev) * signals in the ringbuffer. */ uint32_t ofs = (counter.seen + j) % TEVENT_SA_INFO_QUEUE_COUNT; - se->handler(ev, se, i, 1, - (void*)&sig_state->sig_info[i][ofs], - se->private_data); - if (!exists) { + bool removed = false; + + ret = tevent_common_invoke_signal_handler( + se, i, 1, + (void*)&sig_state->sig_info[i][ofs], + &removed); + if (ret != 0) { + tevent_abort(ev, "tevent_common_invoke_signal_handler() failed"); + } + if (removed) { break; } } -#ifdef SA_RESETHAND - if (exists && (se->sa_flags & SA_RESETHAND)) { - talloc_free(se); - } -#endif - talloc_free(exists); continue; } #endif - se->handler(ev, se, i, count, NULL, se->private_data); -#ifdef SA_RESETHAND - if (exists && (se->sa_flags & SA_RESETHAND)) { - talloc_free(se); + + ret = tevent_common_invoke_signal_handler(se, i, count, + NULL, NULL); + if (ret != 0) { + tevent_abort(ev, "tevent_common_invoke_signal_handler() failed"); } -#endif - talloc_free(exists); } #ifdef SA_SIGINFO