MINOR: lua-thread: Store each function reference and init reference in array

The goal is to allow execution of one main lua state per thread.

The array introduces storage of one reference per thread, because each
lua state can have different reference id for a same function. A function
returns the preferred state id according to configuration and current
thread id.
diff --git a/include/haproxy/hlua-t.h b/include/haproxy/hlua-t.h
index 246504d..f843ebd 100644
--- a/include/haproxy/hlua-t.h
+++ b/include/haproxy/hlua-t.h
@@ -113,7 +113,7 @@
 struct hlua_function {
 	struct list l;
 	char *name;
-	int function_ref;
+	int function_ref[MAX_THREADS + 1];
 	int nargs;
 };
 
diff --git a/src/hlua.c b/src/hlua.c
index 756b166..9d49975 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -130,6 +130,12 @@
  */
 static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
 
+/* This variable is used only during initialization to identify the Lua state
+ * currently being initialized. 0 is the common lua state, 1 to n are the Lua
+ * states dedicated to each thread (in this case hlua_state_id==tid+1).
+ */
+static int hlua_state_id;
+
 #define SET_SAFE_LJMP_L(__L, __HLUA) \
 	({ \
 		int ret; \
@@ -195,7 +201,7 @@
 #endif
 
 /* List head of the function called at the initialisation time. */
-struct list hlua_init_functions = LIST_HEAD_INIT(hlua_init_functions);
+struct list hlua_init_functions[MAX_THREADS + 1];
 
 /* The following variables contains the reference of the different
  * Lua classes. These references are useful for identify metadata
@@ -286,14 +292,25 @@
 static inline struct hlua_function *new_hlua_function()
 {
 	struct hlua_function *fcn;
+	int i;
 
 	fcn = calloc(1, sizeof(*fcn));
 	if (!fcn)
 		return NULL;
 	LIST_ADDQ(&referenced_functions, &fcn->l);
+	for (i = 0; i < MAX_THREADS + 1; i++)
+		fcn->function_ref[i] = -1;
 	return fcn;
 }
 
+/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
+static inline int fcn_ref_to_stack_id(struct hlua_function *fcn)
+{
+	if (fcn->function_ref[0] == -1)
+		return tid + 1;
+	return 0;
+}
+
 /* Used to check an Lua function type in the stack. It creates and
  * returns a reference of the function. This function throws an
  * error if the rgument is not a "function".
@@ -6344,7 +6361,7 @@
 		WILL_LJMP(luaL_error(L, "Lua out of memory error."));
 
 	init->function_ref = ref;
-	LIST_ADDQ(&hlua_init_functions, &init->l);
+	LIST_ADDQ(&hlua_init_functions[hlua_state_id], &init->l);
 	return 0;
 }
 
@@ -6377,7 +6394,7 @@
 		state_id = hlua->state_id;
 	else
 		/* we are in initialization mode */
-		state_id = 0;
+		state_id = hlua_state_id;
 
 	hlua = pool_alloc(pool_head_hlua);
 	if (!hlua)
@@ -6427,7 +6444,7 @@
 			SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
 			return 0;
 		}
-		if (!hlua_ctx_init(stream->hlua, 0, stream->task, 0)) {
+		if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
 			SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
 			return 0;
 		}
@@ -6454,7 +6471,7 @@
 		}
 
 		/* Restore the function in the stack. */
-		lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref);
+		lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
 
 		/* convert input sample and pust-it in the stack. */
 		if (!lua_checkstack(stream->hlua->T, 1)) {
@@ -6560,7 +6577,7 @@
 			SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
 			return 0;
 		}
-		if (!hlua_ctx_init(stream->hlua, 0, stream->task, 0)) {
+		if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
 			SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
 			return 0;
 		}
@@ -6587,7 +6604,7 @@
 		}
 
 		/* Restore the function in the stack. */
-		lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref);
+		lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
 
 		/* push arguments in the stack. */
 		if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
@@ -6710,7 +6727,7 @@
 	fcn->name = strdup(name);
 	if (!fcn->name)
 		WILL_LJMP(luaL_error(L, "Lua out of memory error."));
-	fcn->function_ref = ref;
+	fcn->function_ref[hlua_state_id] = ref;
 
 	/* List head */
 	sck->list.n = sck->list.p = NULL;
@@ -6778,7 +6795,7 @@
 	fcn->name = strdup(name);
 	if (!fcn->name)
 		WILL_LJMP(luaL_error(L, "Lua out of memory error."));
-	fcn->function_ref = ref;
+	fcn->function_ref[hlua_state_id] = ref;
 
 	/* List head */
 	sfk->list.n = sfk->list.p = NULL;
@@ -6862,7 +6879,7 @@
 			         rule->arg.hlua_rule->fcn->name);
 			goto end;
 		}
-		if (!hlua_ctx_init(s->hlua, 0, s->task, 0)) {
+		if (!hlua_ctx_init(s->hlua, fcn_ref_to_stack_id(rule->arg.hlua_rule->fcn), s->task, 0)) {
 			SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
 			         rule->arg.hlua_rule->fcn->name);
 			goto end;
@@ -6892,7 +6909,7 @@
 		}
 
 		/* Restore the function in the stack. */
-		lua_rawgeti(s->hlua->T, LUA_REGISTRYINDEX, rule->arg.hlua_rule->fcn->function_ref);
+		lua_rawgeti(s->hlua->T, LUA_REGISTRYINDEX, rule->arg.hlua_rule->fcn->function_ref[s->hlua->state_id]);
 
 		/* Create and and push object stream in the stack. */
 		if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
@@ -7047,7 +7064,7 @@
 	 * permits to save performances because a systematic
 	 * Lua initialization cause 5% performances loss.
 	 */
-	if (!hlua_ctx_init(hlua, 0, task, 0)) {
+	if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
 		SEND_ERR(px, "Lua applet tcp '%s': can't initialize Lua context.\n",
 		         ctx->rule->arg.hlua_rule->fcn->name);
 		return 0;
@@ -7076,7 +7093,7 @@
 	}
 
 	/* Restore the function in the stack. */
-	lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref);
+	lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
 
 	/* Create and and push object stream in the stack. */
 	if (!hlua_applet_tcp_new(hlua->T, ctx)) {
@@ -7240,7 +7257,7 @@
 	 * permits to save performances because a systematic
 	 * Lua initialization cause 5% performances loss.
 	 */
-	if (!hlua_ctx_init(hlua, 0, task, 0)) {
+	if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
 		SEND_ERR(px, "Lua applet http '%s': can't initialize Lua context.\n",
 		         ctx->rule->arg.hlua_rule->fcn->name);
 		return 0;
@@ -7269,7 +7286,7 @@
 	}
 
 	/* Restore the function in the stack. */
-	lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref);
+	lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
 
 	/* Create and and push object stream in the stack. */
 	if (!hlua_applet_http_new(hlua->T, ctx)) {
@@ -7643,7 +7660,7 @@
 		fcn->name = strdup(name);
 		if (!fcn->name)
 			WILL_LJMP(luaL_error(L, "Lua out of memory error."));
-		fcn->function_ref = ref;
+		fcn->function_ref[hlua_state_id] = ref;
 
 		/* Set the expected number od arguments. */
 		fcn->nargs = nargs;
@@ -7766,7 +7783,7 @@
 	if (!fcn->name)
 		WILL_LJMP(luaL_error(L, "Lua out of memory error."));
 	snprintf((char *)fcn->name, len, "<lua.%s>", name);
-	fcn->function_ref = ref;
+	fcn->function_ref[hlua_state_id] = ref;
 
 	/* List head */
 	akl->list.n = akl->list.p = NULL;
@@ -7835,7 +7852,7 @@
 	appctx->ctx.hlua_cli.task->process = hlua_applet_wakeup;
 
 	/* Initialises the Lua context */
-	if (!hlua_ctx_init(hlua, 0, appctx->ctx.hlua_cli.task, 0)) {
+	if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(fcn), appctx->ctx.hlua_cli.task, 0)) {
 		SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
 		goto error;
 	}
@@ -7857,7 +7874,7 @@
 	}
 
 	/* Restore the function in the stack. */
-	lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref);
+	lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[hlua->state_id]);
 
 	/* Once the arguments parsed, the CLI is like an AppletTCP,
 	 * so push AppletTCP in the stack.
@@ -8065,7 +8082,7 @@
 		strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
 	}
 	strncat((char *)fcn->name, ">", len);
-	fcn->function_ref = ref_io;
+	fcn->function_ref[hlua_state_id] = ref_io;
 
 	/* Fill last entries. */
 	cli_kws->kw[0].private = fcn;
@@ -8226,6 +8243,7 @@
 		return -1;
 	}
 
+	hlua_state_id = 0;
 	return hlua_load_state(args[1], hlua_states[0], err);
 }
 
@@ -8323,7 +8341,7 @@
 
 	hlua_fcn_post_init(L);
 
-	list_for_each_entry(init, &hlua_init_functions, l) {
+	list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
 		lua_rawgeti(L, LUA_REGISTRYINDEX, init->function_ref);
 
 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
@@ -8394,7 +8412,9 @@
 	}
 #endif
 
-	return hlua_post_init_state(hlua_states[0]);
+	/* Perform post init of common thread */
+	hlua_state_id = 0;
+	return hlua_post_init_state(hlua_states[hlua_state_id]);
 }
 
 /* The memory allocator used by the Lua stack. <ud> is a pointer to the
@@ -9038,6 +9058,14 @@
 }
 
 void hlua_init(void) {
+	int i;
+
+	/* Init post init function list head */
+	for (i = 0; i < MAX_THREADS + 1; i++)
+		LIST_INIT(&hlua_init_functions[i]);
+
+	/* Init state for common/shared lua parts */
+	hlua_state_id = 0;
 	hlua_states[0] = hlua_init_state(0);
 }