From: William Lallemand Date: Fri, 12 Apr 2019 14:09:22 +0000 (+0200) Subject: MEDIUM: mworker-prog: implements 'option start-on-reload' X-Git-Tag: v2.0-dev3~262 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bd3de3efb7125f2547b52fd682ce9920c9d7552d;p=thirdparty%2Fhaproxy.git MEDIUM: mworker-prog: implements 'option start-on-reload' This option is already the default, but its opposite 'no option start-on-reload' allows the master to keep a previous instance of a program and don't start a new one upon a reload. The old program will then appear as a current one in "show proc" and could also trigger an exit-on-failure upon a segfault. --- diff --git a/include/types/global.h b/include/types/global.h index 607ba2d96f..3216b5b168 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -187,6 +187,8 @@ struct global { #define PROC_O_TYPE_PROG 0x00000004 /* 0x00000008 unused */ #define PROC_O_LEAVING 0x00000010 /* this process should be leaving */ +/* 0x00000020 to 0x00000080 unused */ +#define PROC_O_START_RELOAD 0x00000100 /* Start the process even if the master was re-executed */ /* * Structure used to describe the processes in master worker mode diff --git a/src/mworker-prog.c b/src/mworker-prog.c index 340f8883de..8eefd85bad 100644 --- a/src/mworker-prog.c +++ b/src/mworker-prog.c @@ -35,13 +35,63 @@ int mworker_ext_launch_all() { int ret; struct mworker_proc *child; + struct mworker_proc *tmp; + int reexec = 0; if (!use_program) return 0; + reexec = getenv("HAPROXY_MWORKER_REEXEC") ? 1 : 0; + /* find the right mworker_proc */ - list_for_each_entry(child, &proc_list, list) { + list_for_each_entry_safe(child, tmp, &proc_list, list) { if (child->reloads == 0 && child->type == 'e') { + + if (reexec && (!(child->options & PROC_O_START_RELOAD))) { + struct mworker_proc *old_child; + + /* + * This is a reload and we don't want to fork a + * new program so have to remove the entry in + * the list. + * + * But before that, we need to mark the + * previous program as not leaving, if we find one. + */ + + list_for_each_entry(old_child, &proc_list, list) { + if (old_child->type != 'e' || (!(old_child->options & PROC_O_LEAVING))) + continue; + + if (!strcmp(old_child->id, child->id)) + old_child->options &= ~PROC_O_LEAVING; + } + + + LIST_DEL(&child->list); + if (child->command) { + int i; + + for (i = 0; child->command[i]; i++) { + if (child->command[i]) { + free(child->command[i]); + child->command[i] = NULL; + } + } + free(child->command); + child->command = NULL; + } + if (child->id) { + free(child->id); + child->id = NULL; + } + + free(child); + child = NULL; + + continue; + } + child->timestamp = now.tv_sec; ret = fork(); @@ -109,6 +159,7 @@ int cfg_parse_program(const char *file, int linenum, char **args, int kwm) ext_child->timestamp = -1; ext_child->ipc_fd[0] = -1; ext_child->ipc_fd[1] = -1; + ext_child->options |= PROC_O_START_RELOAD; /* restart the programs by default */ LIST_INIT(&ext_child->list); list_for_each_entry(child, &proc_list, list) { @@ -162,6 +213,29 @@ int cfg_parse_program(const char *file, int linenum, char **args, int kwm) } ext_child->command[i] = NULL; + } else if (!strcmp(args[0], "option")) { + + if (*(args[1]) == '\0') { + ha_alert("parsing [%s:%d]: '%s' expects an option name.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto error; + } + + if (strcmp(args[1], "start-on-reload") == 0) { + if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) + goto error; + if (kwm == KWM_STD) + ext_child->options |= PROC_O_START_RELOAD; + else if (kwm == KWM_NO) + ext_child->options &= ~PROC_O_START_RELOAD; + goto out; + + } else { + ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto error; + } } else { ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "program"); err_code |= ERR_ALERT | ERR_FATAL; @@ -194,6 +268,7 @@ error: free(ext_child); ext_child = NULL; +out: return err_code; }