Bug 84659

Summary: sd_event fails miserably with more than one child process
Product: systemd Reporter: Hristo Venev <hristo>
Component: generalAssignee: Zbigniew Jedrzejewski-Szmek <zbyszek>
Status: RESOLVED FIXED QA Contact: systemd-bugs
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: Other   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:

Description Hristo Venev 2014-10-04 10:33:38 UTC
When a child event is disabled (in order to be freed) and there is no SIGCHLD signal event, sd_event_source_set_enabled will disable SIGCHLD even if there are other child events.

My fix also removes some unneeded signalfd updates.

diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index b56182d..42b176b 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -1055,11 +1055,9 @@ _public_ int sd_event_add_child(
                 return r;
         }
 
-        e->n_enabled_child_sources ++;
-
         assert_se(sigaddset(&e->sigset, SIGCHLD) == 0);
 
-        if (!e->signal_sources || !e->signal_sources[SIGCHLD]) {
+        if ((!e->signal_sources || !e->signal_sources[SIGCHLD]) && e->n_enabled_child_sources == 0) {
                 r = event_update_signal_fd(e);
                 if (r < 0) {
                         source_free(s);
@@ -1067,6 +1065,8 @@ _public_ int sd_event_add_child(
                 }
         }
 
+        e->n_enabled_child_sources ++;
+
         e->need_process_child = true;
 
         if (ret)
@@ -1451,7 +1451,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
                         assert(s->event->n_enabled_child_sources > 0);
                         s->event->n_enabled_child_sources--;
 
-                        if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
+                        if ((!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) && s->event->n_enabled_child_sources == 0) {
                                 assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
                                 event_update_signal_fd(s->event);
                         }
@@ -1511,12 +1511,12 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
 
                 case SOURCE_CHILD:
                         if (s->enabled == SD_EVENT_OFF) {
-                                s->event->n_enabled_child_sources++;
-
-                                if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) {
+                                if ((!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) && s->event->n_enabled_child_sources == 0) {
                                         assert_se(sigaddset(&s->event->sigset, SIGCHLD) == 0);
                                         event_update_signal_fd(s->event);
                                 }
+
+                                s->event->n_enabled_child_sources++;
                         }
 
                         s->enabled = m;
Comment 1 Zbigniew Jedrzejewski-Szmek 2014-10-08 23:44:39 UTC
A more extensive fix based on this patch applied as http://cgit.freedesktop.org/systemd/systemd/commit/?id=4807d2d068.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.