MEDIUM: vars: Add a per-process scope for variables

Now it is possible to use variables attached to a process. The scope name is
'proc'. These variables are released only when HAProxy is stopped.

'tune.vars.proc-max-size' directive has been added to confiure the maximum
amount of memory used by "proc" variables. And because memory accounting is
hierachical for variables, memory for "proc" vars includes memory for "sess"
vars.
diff --git a/src/haproxy.c b/src/haproxy.c
index c40813b..728c8e5 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -109,6 +109,7 @@
 #include <proto/signal.h>
 #include <proto/task.h>
 #include <proto/dns.h>
+#include <proto/vars.h>
 
 #ifdef USE_OPENSSL
 #include <proto/ssl_sock.h>
@@ -734,6 +735,9 @@
 	/* Initialise lua. */
 	hlua_init();
 
+	/* Initialize process vars */
+	vars_init(&global.vars, SCOPE_PROC);
+
 	global.tune.options |= GTUNE_USE_SELECT;  /* select() is always available */
 #if defined(ENABLE_POLL)
 	global.tune.options |= GTUNE_USE_POLL;
@@ -1675,6 +1679,8 @@
 		free(wl);
 	}
 
+	vars_prune(&global.vars, NULL, NULL);
+
 	pool_destroy2(pool2_stream);
 	pool_destroy2(pool2_session);
 	pool_destroy2(pool2_connection);
diff --git a/src/vars.c b/src/vars.c
index 8322982..dcdf1b5 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -26,6 +26,7 @@
 /* This array of int contains the system limits per context. */
 static unsigned int var_global_limit = 0;
 static unsigned int var_global_size = 0;
+static unsigned int var_proc_limit = 0;
 static unsigned int var_sess_limit = 0;
 static unsigned int var_txn_limit = 0;
 static unsigned int var_reqres_limit = 0;
@@ -45,7 +46,10 @@
 		/* fall through */
 	case SCOPE_SESS:
 		sess->vars.size += size;
-		var_global_size += size;
+		/* fall through */
+	case SCOPE_PROC:
+		global.vars.size += size;
+		var_global_size   += size;
 	}
 }
 
@@ -71,6 +75,10 @@
 	case SCOPE_SESS:
 		if (var_sess_limit && sess->vars.size + size > var_sess_limit)
 			return 0;
+		/* fall through */
+	case SCOPE_PROC:
+		if (var_proc_limit && global.vars.size + size > var_proc_limit)
+			return 0;
 		if (var_global_limit && var_global_size + size > var_global_limit)
 			return 0;
 	}
@@ -125,8 +133,9 @@
 		pool_free2(var_pool, var);
 		size += sizeof(struct var);
 	}
-	vars->size      -= size;
-	var_global_size -= size;
+	vars->size       -= size;
+	global.vars.size -= size;
+	var_global_size  -= size;
 }
 
 /* This function init a list of variabes. */
@@ -162,7 +171,12 @@
 	}
 
 	/* Check scope. */
-	if (len > 5 && strncmp(name, "sess.", 5) == 0) {
+	if (len > 5 && strncmp(name, "proc.", 5) == 0) {
+		name += 5;
+		len -= 5;
+		*scope = SCOPE_PROC;
+	}
+	else if (len > 5 && strncmp(name, "sess.", 5) == 0) {
 		name += 5;
 		len -= 5;
 		*scope = SCOPE_SESS;
@@ -184,7 +198,7 @@
 	}
 	else {
 		memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
-		               "The scope can be 'sess', 'txn', 'req' or 'res'", name);
+		               "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
 		return NULL;
 	}
 
@@ -246,6 +260,9 @@
 
 	/* Check the availibity of the variable. */
 	switch (var_desc->scope) {
+	case SCOPE_PROC:
+		vars = &global.vars;
+		break;
 	case SCOPE_SESS:
 		vars = &smp->sess->vars;
 		break;
@@ -369,6 +386,7 @@
 	struct vars *vars;
 
 	switch (scope) {
+	case SCOPE_PROC: vars = &global.vars;  break;
 	case SCOPE_SESS: vars = &smp->sess->vars;  break;
 	case SCOPE_TXN:  vars = &smp->strm->vars_txn;    break;
 	case SCOPE_REQ:
@@ -461,6 +479,7 @@
 
 	/* Select "vars" pool according with the scope. */
 	switch (scope) {
+	case SCOPE_PROC: vars = &global.vars;  break;
 	case SCOPE_SESS: vars = &smp->sess->vars;  break;
 	case SCOPE_TXN:  vars = &smp->strm->vars_txn;    break;
 	case SCOPE_REQ:
@@ -494,6 +513,7 @@
 
 	/* Select "vars" pool according with the scope. */
 	switch (var_desc->scope) {
+	case SCOPE_PROC: vars = &global.vars;  break;
 	case SCOPE_SESS: vars = &smp->sess->vars;  break;
 	case SCOPE_TXN:  vars = &smp->strm->vars_txn;    break;
 	case SCOPE_REQ:
@@ -653,6 +673,13 @@
 	return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
 }
 
+static int vars_max_size_proc(char **args, int section_type, struct proxy *curpx,
+                                struct proxy *defpx, const char *file, int line,
+                                char **err)
+{
+	return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_proc_limit);
+}
+
 static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
                               struct proxy *defpx, const char *file, int line,
                               char **err)
@@ -676,7 +703,7 @@
 
 static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
 
-	{ "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L5CLI },
+	{ "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
 	{ /* END */ },
 }};
 
@@ -712,6 +739,7 @@
 
 static struct cfg_kw_list cfg_kws = {{ },{
 	{ CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
+	{ CFG_GLOBAL, "tune.vars.proc-max-size",   vars_max_size_proc   },
 	{ CFG_GLOBAL, "tune.vars.sess-max-size",   vars_max_size_sess   },
 	{ CFG_GLOBAL, "tune.vars.txn-max-size",    vars_max_size_txn    },
 	{ CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },