summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2012-01-28 22:18:00 +0100
committerStefan Metzmacher <metze@samba.org>2012-02-09 10:15:27 +0100
commitb5436fde5bbe5b849212258088add492ee8fc4ce (patch)
tree71d0f52eb5552476ffd99a72ff08aa699c82e246
parent4328f3ccf37d9a1baadbc55f658902e3b16ff125 (diff)
downloadsamba-b5436fde5bbe5b849212258088add492ee8fc4ce.tar.gz
samba-b5436fde5bbe5b849212258088add492ee8fc4ce.tar.bz2
samba-b5436fde5bbe5b849212258088add492ee8fc4ce.zip
tevent: Fix deleting signal events from within themselves
Signed-off-by: Stefan Metzmacher <metze@samba.org>
-rw-r--r--lib/tevent/tevent_signal.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index fabe72cdc8..248dd35883 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -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