MINOR: mworker: support a configurable maximum number of reloads

This patch implements a new global parameter for the master-worker mode.
When setting the mworker-max-reloads value, a worker receive a SIGTERM
if its number of reloads is greater than this value.
diff --git a/src/haproxy.c b/src/haproxy.c
index 8ab0c2e..4c37125 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -2780,6 +2780,10 @@
 	if (nb_oldpids && !(global.mode & MODE_MWORKER_WAIT))
 		nb_oldpids = tell_old_pids(oldpids_sig);
 
+	/* send a SIGTERM to workers who have a too high reloads number  */
+	if ((global.mode & MODE_MWORKER) && !(global.mode & MODE_MWORKER_WAIT))
+		mworker_kill_max_reloads(SIGTERM);
+
 	if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL)) {
 		nb_oldpids = 0;
 		free(oldpids);
diff --git a/src/mworker.c b/src/mworker.c
index abc67bd..8df748d 100644
--- a/src/mworker.c
+++ b/src/mworker.c
@@ -17,6 +17,7 @@
 #include <string.h>
 #include <sys/wait.h>
 
+#include <common/cfgparse.h>
 #include <common/initcall.h>
 #include <common/mini-clist.h>
 
@@ -41,6 +42,7 @@
 #endif
 
 static int exitcode = -1;
+static int max_reloads = -1; /* number max of reloads a worker can have until they are killed */
 
 /* ----- children processes handling ----- */
 
@@ -59,6 +61,16 @@
 	}
 }
 
+void mworker_kill_max_reloads(int sig)
+{
+	struct mworker_proc *child;
+
+	list_for_each_entry(child, &proc_list, list) {
+		if (max_reloads != -1 && (child->options & PROC_O_TYPE_WORKER) &&
+		    (child->pid > 0) && (child->reloads > max_reloads))
+			kill(child->pid, sig);
+	}
+}
 
 /* return 1 if a pid is a current child otherwise 0 */
 int mworker_current_child(int pid)
@@ -515,6 +527,41 @@
 }
 
 
+static int mworker_parse_global_max_reloads(char **args, int section_type, struct proxy *curpx,
+           struct proxy *defpx, const char *file, int linenum, char **err)
+{
+
+	int err_code = 0;
+
+	if (alertif_too_many_args(1, file, linenum, args, &err_code))
+		goto out;
+
+	if (*(args[1]) == 0) {
+		memprintf(err, "%sparsing [%s:%d] : '%s' expects an integer argument.\n", *err, file, linenum, args[0]);
+		err_code |= ERR_ALERT | ERR_FATAL;
+		goto out;
+	}
+
+	max_reloads = atol(args[1]);
+	if (max_reloads < 0) {
+		memprintf(err, "%sparsing [%s:%d] '%s' : invalid value %d, must be >= 0", *err, file, linenum, args[0], max_reloads);
+		err_code |= ERR_ALERT | ERR_FATAL;
+		goto out;
+	}
+
+out:
+	return err_code;
+}
+
+
+static struct cfg_kw_list mworker_kws = {{ }, {
+	{ CFG_GLOBAL, "mworker-max-reloads", mworker_parse_global_max_reloads },
+	{ 0, NULL, NULL },
+}};
+
+INITCALL1(STG_REGISTER, cfg_register_keywords, &mworker_kws);
+
+
 /* register cli keywords */
 static struct cli_kw_list cli_kws = {{ },{
 	{ { "@<relative pid>", NULL }, "@<relative pid> : send a command to the <relative pid> process", NULL, cli_io_handler_show_proc, NULL, NULL, ACCESS_MASTER_ONLY},