tevent: split out tevent_common_invoke_signal_handler()
authorStefan Metzmacher <metze@samba.org>
Tue, 22 Jul 2014 11:01:01 +0000 (13:01 +0200)
committerRalph Boehme <slow@samba.org>
Wed, 11 Jul 2018 21:04:20 +0000 (23:04 +0200)
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 <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
lib/tevent/ABI/tevent-0.9.36.sigs
lib/tevent/tevent_internal.h
lib/tevent/tevent_signal.c

index 8a9d1a6ba1055af094380a4a950427169d8a9245..230f6b9f26b1f7454d8ac718ee246ceb8e519bb0 100644 (file)
@@ -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 *)
index 7e15a59d3fb4df607febbe65389c77256e3e7aaf..f36cd219f68882b3a3bcb7a3f6cd29d035f8c9a7 100644 (file)
@@ -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);
index ef23024331681fb993eca3493a7aa1667a26bc00..a787f97b9649384d3f8e5bc6af4c90999b7fc26c 100644 (file)
@@ -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