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.
This commit is contained in:
William Lallemand 2025-11-17 18:30:20 +01:00
parent b38405d156
commit 709cde6d08
3 changed files with 31 additions and 17 deletions

View File

@ -2652,6 +2652,8 @@ static int _send_status(char **args, char *payload, struct appctx *appctx, void
if (global.tune.options & GTUNE_USE_SYSTEMD) if (global.tune.options & GTUNE_USE_SYSTEMD)
sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid()); 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 /* master and worker have successfully started, now we can set quiet mode
* if MODE_DAEMON * if MODE_DAEMON
*/ */

View 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 */ global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
} }
mworker_unblock_signals();
/* enter in master polling loop */ /* enter in master polling loop */
mworker_run_master(); mworker_run_master();
} }

View File

@ -278,8 +278,35 @@ void mworker_block_signals()
ha_sigmask(SIG_SETMASK, &set, NULL); 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() 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(); haproxy_unblock_signals();
} }
@ -1117,23 +1144,7 @@ static void mworker_loop()
/* Busy polling makes no sense in the master :-) */ /* Busy polling makes no sense in the master :-) */
global.tune.options &= ~GTUNE_BUSY_POLLING; global.tune.options &= ~GTUNE_BUSY_POLLING;
mworker_unblock_sigchld();
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_cleantasks(); mworker_cleantasks();
mworker_catch_sigchld(NULL); /* ensure we clean the children in case mworker_catch_sigchld(NULL); /* ensure we clean the children in case