MEDIUM: mworker: use the haproxy poll loop
In order to reorganize the code of the master worker, the mworker_wait()
function which was the main function was split. This function was
handling a wait() loop, but it does not need it anymore since the code
will use the poll loop of haproxy instead.
The function was split in several functions:
- mworker_catch_sigterm() which is a signal handler for SIGTERM ans
SIGUSR1 that sends the signals to the workers
- mworker_catch_sigchld() which is the code handling the leaving of a
child
- mworker_catch_sighup which basically call the mworker_restart()
function
- mworker_loop() which is the function calling the main poll loop in the
master
diff --git a/src/haproxy.c b/src/haproxy.c
index a0963a0..d40316a 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -213,6 +213,8 @@
struct task *global_listener_queue_task;
static struct task *manage_global_listener_queue(struct task *t, void *context, unsigned short state);
+static void *run_thread_poll_loop(void *data);
+
/* bitfield of a few warnings to emit just once (WARN_*) */
unsigned int warned = 0;
@@ -481,11 +483,6 @@
return 0;
}
-static void mworker_signalhandler(int signum)
-{
- caught_signal = signum;
-}
-
static void mworker_block_signals()
{
sigset_t set;
@@ -681,6 +678,8 @@
next_argv[next_argc++] = NULL;
}
+ deinit_pollers(); /* we don't want to leak the poller fd */
+
ha_warning("Reexecuting Master process\n");
execvp(next_argv[0], next_argv);
@@ -692,51 +691,41 @@
return;
}
-
/*
- * Wait for every children to exit
+ * When called, this function reexec haproxy with -sf followed by current
+ * children PIDs and possibily old children PIDs if they didn't leave yet.
*/
-
-static void mworker_wait()
+static void mworker_catch_sighup(struct sig_handler *sh)
{
- int exitpid = -1;
- int status = 0;
+ mworker_reload();
+}
-restart_wait:
+static void mworker_catch_sigterm(struct sig_handler *sh)
+{
+ int sig = sh->arg;
#if defined(USE_SYSTEMD)
- if (global.tune.options & GTUNE_USE_SYSTEMD)
- sd_notifyf(0, "READY=1\nMAINPID=%lu", (unsigned long)getpid());
+ if (global.tune.options & GTUNE_USE_SYSTEMD) {
+ sd_notify(0, "STOPPING=1");
+ }
#endif
-
- mworker_unblock_signals();
+ ha_warning("Exiting Master process...\n");
+ mworker_kill(sig);
+}
- while (1) {
+/*
+ * Wait for every children to exit
+ */
- while (((exitpid = wait(&status)) == -1) && errno == EINTR) {
- int sig = caught_signal;
- if (sig == SIGUSR2 || sig == SIGHUP) {
- mworker_reload();
- /* should reach there only if it fail */
- goto restart_wait;
- } else {
-#if defined(USE_SYSTEMD)
- if ((global.tune.options & GTUNE_USE_SYSTEMD) && (sig == SIGUSR1 || sig == SIGTERM)) {
- sd_notify(0, "STOPPING=1");
- }
-#endif
- ha_warning("Exiting Master process...\n");
- mworker_kill(sig);
- }
- caught_signal = 0;
- }
+static void mworker_catch_sigchld(struct sig_handler *sh)
+{
+ int exitpid = -1;
+ int status = 0;
- if (exitpid == -1 && errno == ECHILD) {
- ha_warning("All workers exited. Exiting... (%d)\n", status);
- atexit_flag = 0;
- exit(status); /* parent must leave using the latest status code known */
- }
+restart_wait:
+ exitpid = waitpid(-1, &status, WNOHANG);
+ if (exitpid > 0) {
if (WIFEXITED(status))
status = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
@@ -762,9 +751,47 @@
delete_oldpid(exitpid);
}
}
+ /* do it again to check if it was the last worker */
+ goto restart_wait;
}
+ /* Better rely on the system than on a list of process to check if it was the last one */
+ else if (exitpid == -1 && errno == ECHILD) {
+ ha_warning("All workers exited. Exiting... (%d)\n", status);
+ atexit_flag = 0;
+ exit(status); /* parent must leave using the latest status code known */
+ }
+
}
+static void mworker_loop()
+{
+
+#if defined(USE_SYSTEMD)
+ if (global.tune.options & GTUNE_USE_SYSTEMD)
+ sd_notifyf(0, "READY=1\nMAINPID=%lu", (unsigned long)getpid());
+#endif
+
+ signal_register_fct(SIGTERM, mworker_catch_sigterm, SIGTERM);
+ signal_register_fct(SIGUSR1, mworker_catch_sigterm, SIGUSR1);
+ 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_cleanlisteners();
+
+ global.nbthread = 1;
+ relative_pid = 1;
+ pid_bit = 1;
+
+ jobs++; /* this is the "master" job, we want to take care of the
+ signals even if there is no listener so the poll loop don't
+ leave */
+
+ fork_poller();
+ run_thread_poll_loop((int []){0});
+}
/*
* Reexec the process in failure mode, instead of exiting
@@ -1501,7 +1528,7 @@
if ((global.mode & MODE_MWORKER) && (getenv("HAPROXY_MWORKER_WAIT_ONLY") != NULL)) {
unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
- mworker_wait();
+ mworker_loop();
}
if ((global.mode & MODE_MWORKER) && (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
@@ -2822,8 +2849,6 @@
if (proc == global.nbproc) {
if (global.mode & MODE_MWORKER) {
- mworker_cleanlisteners();
- deinit_pollers();
if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
(global.mode & MODE_DAEMON)) {
@@ -2835,7 +2860,7 @@
global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
}
- mworker_wait();
+ mworker_loop();
/* should never get there */
exit(EXIT_FAILURE);
}