]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mworker: signals inconsistencies during startup and reload
authorWilliam Lallemand <wlallemand@haproxy.com>
Mon, 17 Nov 2025 17:30:20 +0000 (18:30 +0100)
committerWilliam Lallemand <wlallemand@haproxy.com>
Tue, 18 Nov 2025 09:05:42 +0000 (10:05 +0100)
Since haproxy 3.1, the master-worker mode changed to let the worker
parse the configuration instead of the master.

Previously, signals were blocked during configuration parsing and
unblocked before entering the polling loop of the master. This way it
was impossible to start a reload during the configuration parsing.

But with the new model, the polling loop is started in the master before
the configuration parsing is finished, and the signals are still
unblocked at this step. Meaning that it is possible to start a reload
while the configuration is parsing.

This patch reintroduce the behavior of blocking the signals during
configuration parsing adapted to the new model:

- Before the exec() of the reload, signals are blocked.
- When entering the polling loop, the SIGCHLD is unblocked because it is
  required to get a failure during configuration parsing in the worker
- Once the configuration is parsed, upon success in _send_status() or
  upon failure in run_master_in_recovery_mode() every signals are unblocked.

This patch must be backported as far as 3.1.

src/cli.c
src/haproxy.c
src/mworker.c

index 12cd971fcbf6040921aab6d3ea75f137f6810bb3..fbf8f1d9d064e41e63d681425a6cb2253c2625e2 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -2652,6 +2652,8 @@ static int _send_status(char **args, char *payload, struct appctx *appctx, void
        if (global.tune.options & GTUNE_USE_SYSTEMD)
                sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid());
 
+       mworker_unblock_signals();
+
        /* master and worker have successfully started, now we can set quiet mode
         * if MODE_DAEMON
         */
index fb35ccf40fed238fbb125f522255e083fbfd1766..e1e16878ccd9cfd6428aa15f4d0748584beaca15 100644 (file)
@@ -2601,6 +2601,7 @@ static void run_master_in_recovery_mode(int argc, char **argv)
                global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
        }
 
+       mworker_unblock_signals();
        /* enter in master polling loop */
        mworker_run_master();
 }
index 99bbc07005214cfe5de537b9e4d25d532c8532fd..1e975b81d3031694420fe8577789bd0501fa4bba 100644 (file)
@@ -278,8 +278,35 @@ void mworker_block_signals()
        ha_sigmask(SIG_SETMASK, &set, NULL);
 }
 
+void mworker_unblock_sigchld()
+{
+       sigset_t set;
+
+       signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
+
+       sigemptyset(&set);
+       sigaddset(&set, SIGCHLD);
+
+       ha_sigmask(SIG_UNBLOCK, &set, NULL);
+}
+
 void mworker_unblock_signals()
 {
+       signal_unregister(SIGTTIN);
+       signal_unregister(SIGTTOU);
+       signal_unregister(SIGUSR1);
+       signal_unregister(SIGHUP);
+       signal_unregister(SIGQUIT);
+
+       signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
+       signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
+       signal_register_fct(SIGTTIN, mworker_broadcast_signal, SIGTTIN);
+       signal_register_fct(SIGTTOU, mworker_broadcast_signal, SIGTTOU);
+       signal_register_fct(SIGINT, mworker_catch_sigterm, SIGINT);
+       signal_register_fct(SIGHUP, mworker_catch_sighup, SIGHUP);
+       signal_register_fct(SIGUSR2, mworker_catch_sighup, SIGUSR2);
+       signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
+
        haproxy_unblock_signals();
 }
 
@@ -1117,23 +1144,7 @@ static void mworker_loop()
        /* Busy polling makes no sense in the master :-) */
        global.tune.options &= ~GTUNE_BUSY_POLLING;
 
-
-       signal_unregister(SIGTTIN);
-       signal_unregister(SIGTTOU);
-       signal_unregister(SIGUSR1);
-       signal_unregister(SIGHUP);
-       signal_unregister(SIGQUIT);
-
-       signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
-       signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
-       signal_register_fct(SIGTTIN, mworker_broadcast_signal, SIGTTIN);
-       signal_register_fct(SIGTTOU, mworker_broadcast_signal, SIGTTOU);
-       signal_register_fct(SIGINT, mworker_catch_sigterm, SIGINT);
-       signal_register_fct(SIGHUP, mworker_catch_sighup, SIGHUP);
-       signal_register_fct(SIGUSR2, mworker_catch_sighup, SIGUSR2);
-       signal_register_fct(SIGCHLD, mworker_catch_sigchld, SIGCHLD);
-
-       mworker_unblock_signals();
+       mworker_unblock_sigchld();
        mworker_cleantasks();
 
        mworker_catch_sigchld(NULL); /* ensure we clean the children in case