core/service: rework ExecReload= + Type=notify-reload interaction, add ExecReloadPost=

When Type=notify-reload got introduced, it wasn't intended to be
mutually exclusive with ExecReload=. However, currently ExecReload=
is immediately forked off after the service main process is signaled,
leaving states in between essentially undefined. Given so broken
it is I doubt any sane user is using this setup, hence I took a stab
to rework everything:

1.  Extensions are refreshed (unchanged)
2.  ExecReload= is forked off without signaling the process
3a. If RELOADING=1 is sent during the ExecReload= invocation,
    we'd refrain from signaling the process again, instead
    just transition to SERVICE_RELOAD_NOTIFY directly and
    wait for READY=1
3b. If not, signal the process after ExecReload= finishes
    (from now on the same as Type=notify-reload w/o ExecReload=)
4.  To accomodate the use case of performing post-reload tasks,
    ExecReloadPost= is introduced which executes after READY=1

The new model greatly simplifies things, as no control processes
will be around in SERVICE_RELOAD_SIGNAL and SERVICE_RELOAD_NOTIFY
states.

See also: https://github.com/systemd/systemd/issues/37515#issuecomment-2891229652
This commit is contained in:
Mike Yuan
2025-11-04 12:18:33 +01:00
parent b3c6709fde
commit b03e1b09af
10 changed files with 205 additions and 110 deletions
+2 -1
View File
@@ -224,10 +224,11 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_START_POST] = "start-post",
[SERVICE_RUNNING] = "running",
[SERVICE_EXITED] = "exited",
[SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions",
[SERVICE_RELOAD] = "reload",
[SERVICE_RELOAD_SIGNAL] = "reload-signal",
[SERVICE_RELOAD_NOTIFY] = "reload-notify",
[SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions",
[SERVICE_RELOAD_POST] = "reload-post",
[SERVICE_STOP] = "stop",
[SERVICE_STOP_WATCHDOG] = "stop-watchdog",
[SERVICE_STOP_SIGTERM] = "stop-sigterm",
+2 -1
View File
@@ -131,10 +131,11 @@ typedef enum ServiceState {
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
SERVICE_REFRESH_EXTENSIONS, /* Refreshing extensions for a reload request */
SERVICE_RELOAD, /* Reloading via ExecReload= */
SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */
SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */
SERVICE_REFRESH_EXTENSIONS, /* Refreshing extensions for a reload request */
SERVICE_RELOAD_POST,
SERVICE_MOUNTING, /* Performing a live mount into the namespace of the service */
SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
SERVICE_STOP_WATCHDOG,