b9a53a
From 25b93538eba0275d35ef4b0792c2cd63d63d5e8d Mon Sep 17 00:00:00 2001
b9a53a
From: Franck Bui <fbui@suse.com>
b9a53a
Date: Tue, 19 Mar 2019 10:59:26 +0100
b9a53a
Subject: [PATCH] core: only watch processes when it's really necessary
b9a53a
MIME-Version: 1.0
b9a53a
Content-Type: text/plain; charset=UTF-8
b9a53a
Content-Transfer-Encoding: 8bit
b9a53a
b9a53a
If we know that main pid is our child then it's unnecessary to watch all
b9a53a
other processes of a unit since in this case we will get SIGCHLD when the main
b9a53a
process will exit and will act upon accordingly.
b9a53a
b9a53a
So let's watch all processes only if the main process is not our child since in
b9a53a
this case we need to detect when the cgroup will become empty in order to
b9a53a
figure out when the service becomes dead. This is only needed by cgroupv1.
b9a53a
b9a53a
Thanks Renaud Métrich for backporting this to RHEL.
b9a53a
Resolves: #1744972
b9a53a
---
b9a53a
 src/core/service.c | 15 +++++++++------
b9a53a
 1 file changed, 9 insertions(+), 6 deletions(-)
b9a53a
b9a53a
diff --git a/src/core/service.c b/src/core/service.c
b9a53a
index 310838a5f6..b1ec52d220 100644
b9a53a
--- a/src/core/service.c
b9a53a
+++ b/src/core/service.c
b9a53a
@@ -3410,8 +3410,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
b9a53a
                                 if (main_pid_good(s) <= 0)
b9a53a
                                         service_enter_stop_post(s, f);
b9a53a
 
b9a53a
-                                /* If there is still a service
b9a53a
-                                 * process around, wait until
b9a53a
+                                /* If there is still a service process around, wait until
b9a53a
                                  * that one quit, too */
b9a53a
                                 break;
b9a53a
 
b9a53a
@@ -3433,10 +3432,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
b9a53a
         if (notify_dbus)
b9a53a
                 unit_add_to_dbus_queue(u);
b9a53a
 
b9a53a
-        /* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to watch,
b9a53a
-         * under the assumption that we'll sooner or later get a SIGCHLD for them, as the original process we watched
b9a53a
-         * was probably the parent of them, and they are hence now our children. */
b9a53a
-        (void) unit_enqueue_rewatch_pids(u);
b9a53a
+        /* We watch the main/control process otherwise we can't retrieve the unit they
b9a53a
+         * belong to with cgroupv1. But if they are not our direct child, we won't get a
b9a53a
+         * SIGCHLD for them. Therefore we need to look for others to watch so we can
b9a53a
+         * detect when the cgroup becomes empty. Note that the control process is always
b9a53a
+         * our child so it's pointless to watch all other processes. */
b9a53a
+        if (!control_pid_good(s))
b9a53a
+                if (!s->main_pid_known || s->main_pid_alien)
b9a53a
+                        (void) unit_enqueue_rewatch_pids(u);
b9a53a
 }
b9a53a
 
b9a53a
 static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {