В Mon, 27 Jan 2014 15:48:50 +0100
Lennart Poettering <lenn...@poettering.net> пишет:

> On Sun, 26.01.14 12:09, Andrey Borzenkov (arvidj...@gmail.com) wrote:
> 
> > > > Any advices on how to do that?
> > > > I have both the issue (reproducible on each shutdown) and will to debug.
> > > 
> > > Well, enable the debug shell, and then from there try to figure out why
> > > things are stuck. i.e. whether it is systemd --user that really never
> > > exits. Or whether it actually exits but PID 1 doesn't notice it. And
> > > then if you figured out which of the two cases, you'd have to figure out
> > > why that is...
> > > 
> > I finally managed to reproduce it with user instance running with debug
> > level (before *any* attempt to add debugging, strace, whatever resulted
> > in problem disappearing).
> > 
> > It seems that /bin/kill -RTMIN+24 is being killed itself. I wonder - is
> > it possible that it is the same SIGTERM that is used by PID 1 to stop
> > user@0service?
> 
> Ah, bummer! Yikes!
> 
> Thanks for tracking this done, this really sounds like you nailed the
> problem. Now, how to fix it?
> 
> Hmm, so, I would claim this is a shortcoming of
> KillMode=control-group, which is the default for everything. There has
> been an item on the TODO list to maybe introduce a KillMode=mixed
> setting, which would send SIGTERM only to the main process, and the
> SIGKILL later on to all processes. I am pretty sure that this would
> solve the issue at hand quite nicely here, because the systemd user
> instance would get a nice chance to clean up its own act, before the
> systemd system instance would make tabula rasa...
> 

I still favor alternative approach - let systemd wait for main PID
to exit after ExecStop instead. This is functionally equivalent to the
above with slight advantages

- it will probably decrease number of timeouts because systemd will go
  on killing spree as soon as main PID exits, not after final timeout.

- it is more generic as it allows any available method to trigger
  service stop, not just a signal.

Comments are welcome :)

From: Andrey Borzenkov <arvidj...@gmail.com>
Subject: [PATCH] add WaitForMainPIDOnStop option

WaitForMainPIDOnStop=true will wait for exit of main PID in addition to
command set as ExecStop.

Use it in user@.service to allow user systemd to complete exit transaction
before starting final kill.

---
 man/systemd.service.xml               | 13 +++++++++++++
 src/core/dbus-service.c               |  1 +
 src/core/load-fragment-gperf.gperf.m4 |  1 +
 src/core/service.c                    | 15 +++++++++++++--
 src/core/service.h                    |  1 +
 units/u...@.service.in                |  2 ++
 6 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index d316ab5..c121c95 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -1016,6 +1016,19 @@ ExecStart=/bin/echo $ONE $TWO ${TWO}
                                 <option>none</option>.</para></listitem>
                         </varlistentry>
 
+                        <varlistentry>
+                                
<term><varname>WaitForMainPIDOnStop=</varname></term>
+
+                                <listitem><para>Takes a boolean value
+                                that specifies whether systemd should
+                                additionally wait for the main PID of a service
+                                to exit after executing ExecStop command.
+                                Default is to wait for completion of ExecStop
+                                command only.  Defaults to
+                                <option>no</option>.</para>
+                                </listitem>
+                        </varlistentry>
+
                 </variablelist>
 
                 <para>Check
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 3db9339..35a3c2f 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -54,6 +54,7 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, 
offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, 
offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("GuessMainPID", "b", bus_property_get_bool, 
offsetof(Service, guess_main_pid), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("WaitForMainPIDOnStop", "b", bus_property_get_bool, 
offsetof(Service, stop_waits_for_main_pid), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, 
offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, 
offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), 
SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/load-fragment-gperf.gperf.m4 
b/src/core/load-fragment-gperf.gperf.m4
index 59b2a64..85aaef7 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -167,6 +167,7 @@ Service.PermissionsStartOnly,    config_parse_bool,         
         0,
 Service.RootDirectoryStartOnly,  config_parse_bool,                  0,        
                     offsetof(Service, root_directory_start_only)
 Service.RemainAfterExit,         config_parse_bool,                  0,        
                     offsetof(Service, remain_after_exit)
 Service.GuessMainPID,            config_parse_bool,                  0,        
                     offsetof(Service, guess_main_pid)
+Service.WaitForMainPIDOnStop,    config_parse_bool,                  0,        
                     offsetof(Service, stop_waits_for_main_pid)
 Service.RestartPreventExitStatus, config_parse_set_status,           0,        
                     offsetof(Service, restart_ignore_status)
 Service.SuccessExitStatus,       config_parse_set_status,            0,        
                     offsetof(Service, success_status)
 m4_ifdef(`HAVE_SYSV_COMPAT',
diff --git a/src/core/service.c b/src/core/service.c
index d949f7a..8e0eb6c 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1269,6 +1269,7 @@ static void service_dump(Unit *u, FILE *f, const char 
*prefix) {
                 "%sRootDirectoryStartOnly: %s\n"
                 "%sRemainAfterExit: %s\n"
                 "%sGuessMainPID: %s\n"
+                "%sWaitForMainPIDOnStop: %s\n"
                 "%sType: %s\n"
                 "%sRestart: %s\n"
                 "%sNotifyAccess: %s\n",
@@ -1279,6 +1280,7 @@ static void service_dump(Unit *u, FILE *f, const char 
*prefix) {
                 prefix, yes_no(s->root_directory_start_only),
                 prefix, yes_no(s->remain_after_exit),
                 prefix, yes_no(s->guess_main_pid),
+                prefix, yes_no(s->stop_waits_for_main_pid),
                 prefix, service_type_to_string(s->type),
                 prefix, service_restart_to_string(s->restart),
                 prefix, notify_access_to_string(s->notify_access));
@@ -2953,11 +2955,17 @@ static void service_sigchld_event(Unit *u, pid_t pid, 
int code, int status) {
 
                         case SERVICE_START_POST:
                         case SERVICE_RELOAD:
-                        case SERVICE_STOP:
                                 /* Need to wait until the operation is
                                  * done */
                                 break;
 
+                        case SERVICE_STOP:
+                                /* If requested, wait for both main and control
+                                   PID to finish */
+                                if (s->stop_waits_for_main_pid && 
!control_pid_good(s))
+                                        service_enter_signal(s, 
SERVICE_STOP_SIGTERM, f);
+                                break;
+
                         case SERVICE_START:
                                 if (s->type == SERVICE_ONESHOT) {
                                         /* This was our main goal, so let's go 
on */
@@ -3116,7 +3124,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, 
int code, int status) {
                                 break;
 
                         case SERVICE_STOP:
-                                service_enter_signal(s, SERVICE_STOP_SIGTERM, 
f);
+                                /* If requested, wait for both main and control
+                                   PID to finish */
+                                if (!s->stop_waits_for_main_pid || 
main_pid_good(s) <= 0)
+                                        service_enter_signal(s, 
SERVICE_STOP_SIGTERM, f);
                                 break;
 
                         case SERVICE_STOP_SIGTERM:
diff --git a/src/core/service.h b/src/core/service.h
index 1992926..919d54b 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -163,6 +163,7 @@ struct Service {
         bool root_directory_start_only;
         bool remain_after_exit;
         bool guess_main_pid;
+        bool stop_waits_for_main_pid;
 
         /* If we shut down, remember why */
         ServiceResult result;
diff --git a/units/u...@.service.in b/units/u...@.service.in
index bfc9b70..ac3caf3 100644
--- a/units/u...@.service.in
+++ b/units/u...@.service.in
@@ -14,4 +14,6 @@ User=%i
 PAMName=systemd-user
 Type=notify
 ExecStart=-@rootlibexecdir@/systemd --user
+ExecStop=@KILL@ -TERM $MANAGERPID
+WaitForMainPIDOnStop=yes
 Slice=user-%i.slice
-- 
tg: (2d5bdf5..) u/wait_for_mainPID_on_stop (depends on: master)
_______________________________________________
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel

Reply via email to