From 709cde6d0877f409173d81dd46e1d0f52af92279 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Mon, 17 Nov 2025 18:30:20 +0100 Subject: [PATCH] BUG/MEDIUM: mworker: signals inconsistencies during startup and reload 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 | 2 ++ src/haproxy.c | 1 + src/mworker.c | 45 ++++++++++++++++++++++++++++----------------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/cli.c b/src/cli.c index 12cd971fc..fbf8f1d9d 100644 --- 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 */ diff --git a/src/haproxy.c b/src/haproxy.c index fb35ccf40..e1e16878c 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -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(); } diff --git a/src/mworker.c b/src/mworker.c index 99bbc0700..1e975b81d 100644 --- a/src/mworker.c +++ b/src/mworker.c @@ -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