tevent: Fix deleting signal events from within themselves
authorVolker Lendecke <vl@samba.org>
Sat, 28 Jan 2012 21:18:00 +0000 (22:18 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 9 Feb 2012 09:15:27 +0000 (10:15 +0100)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
lib/tevent/tevent_signal.c

index fabe72cdc88932bbb6b0c2fd35a01f410a7f3227..248dd35883bc29432d9a8dc730e2c0f149d4aa67 100644 (file)
@@ -307,6 +307,15 @@ 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)
+{
+       *s->myself = NULL;
+       return 0;
+}
 
 /*
   check if a signal is pending
@@ -335,6 +344,23 @@ 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;
+
+                       /*
+                        * 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);
+
                        next = sl->next;
 #ifdef SA_SIGINFO
                        if (se->sa_flags & SA_SIGINFO) {
@@ -352,21 +378,26 @@ int tevent_common_check_signal(struct tevent_context *ev)
                                        se->handler(ev, se, i, 1,
                                                    (void*)&sig_state->sig_info[i][ofs], 
                                                    se->private_data);
+                                       if (!exists) {
+                                               break;
+                                       }
                                }
 #ifdef SA_RESETHAND
-                               if (se->sa_flags & 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 (se->sa_flags & SA_RESETHAND) {
+                       if (exists && (se->sa_flags & SA_RESETHAND)) {
                                talloc_free(se);
                        }
 #endif
+                       talloc_free(exists);
                }
 
 #ifdef SA_SIGINFO