From: Thierry Fournier Date: Sat, 28 Nov 2020 16:02:21 +0000 (+0100) Subject: MEDIUM: lua-thread: Apply lock only if the parent state is the main thread X-Git-Tag: v2.4-dev3~111 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7cbe5046e879368b54917a0a2171f729d8bb98d4;p=thirdparty%2Fhaproxy.git MEDIUM: lua-thread: Apply lock only if the parent state is the main thread The goal is to allow execution of one main lua state per thread. This patch opens the way to addition of a per-thread dedicated lua state. By passing the hlua we can figure the original state that's been used and decide to lock or not. --- diff --git a/src/hlua.c b/src/hlua.c index 94bbad7978..b93e46db2f 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -124,14 +124,16 @@ THREAD_LOCAL jmp_buf safe_ljmp_env; static int hlua_panic_safe(lua_State *L) { return 0; } static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); } -#define SET_SAFE_LJMP(__L) \ +#define SET_SAFE_LJMP_L(__L, __HLUA) \ ({ \ int ret; \ - HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock); \ + if ((__HLUA)->state_from == gL.T) \ + HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock); \ if (setjmp(safe_ljmp_env) != 0) { \ lua_atpanic(__L, hlua_panic_safe); \ ret = 0; \ - HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \ + if ((__HLUA)->state_from == gL.T) \ + HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \ } else { \ lua_atpanic(__L, hlua_panic_ljmp); \ ret = 1; \ @@ -142,12 +144,25 @@ static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); /* If we are the last function catching Lua errors, we * must reset the panic function. */ -#define RESET_SAFE_LJMP(__L) \ +#define RESET_SAFE_LJMP_L(__L, __HLUA) \ do { \ lua_atpanic(__L, hlua_panic_safe); \ - HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \ + if ((__HLUA)->state_from == gL.T) \ + HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \ } while(0) +#define SET_SAFE_LJMP(__HLUA) \ + SET_SAFE_LJMP_L((__HLUA)->T, __HLUA) + +#define RESET_SAFE_LJMP(__HLUA) \ + RESET_SAFE_LJMP_L((__HLUA)->T, __HLUA) + +#define SET_SAFE_LJMP_PARENT(__HLUA) \ + SET_SAFE_LJMP_L((__HLUA)->state_from, __HLUA) + +#define RESET_SAFE_LJMP_PARENT(__HLUA) \ + RESET_SAFE_LJMP_L((__HLUA)->state_from, __HLUA) + /* Applet status flags */ #define APPLET_DONE 0x01 /* applet processing is done. */ /* unused: 0x02 */ @@ -1010,30 +1025,30 @@ __LJMP void hlua_yieldk(lua_State *L, int nresults, int ctx, */ int hlua_ctx_init(struct hlua *lua, lua_State *state_from, struct task *task, int already_safe) { - if (!already_safe) { - if (!SET_SAFE_LJMP(state_from)) { - lua->Tref = LUA_REFNIL; - return 0; - } - } lua->Mref = LUA_REFNIL; lua->flags = 0; lua->gc_count = 0; lua->wake_time = TICK_ETERNITY; lua->state_from = state_from; LIST_INIT(&lua->com); + if (!already_safe) { + if (!SET_SAFE_LJMP_PARENT(lua)) { + lua->Tref = LUA_REFNIL; + return 0; + } + } lua->T = lua_newthread(state_from); if (!lua->T) { lua->Tref = LUA_REFNIL; if (!already_safe) - RESET_SAFE_LJMP(state_from); + RESET_SAFE_LJMP_PARENT(lua); return 0; } hlua_sethlua(lua); lua->Tref = luaL_ref(state_from, LUA_REGISTRYINDEX); lua->task = task; if (!already_safe) - RESET_SAFE_LJMP(state_from); + RESET_SAFE_LJMP_PARENT(lua); return 1; } @@ -1052,15 +1067,15 @@ void hlua_ctx_destroy(struct hlua *lua) /* Purge all the pending signals. */ notification_purge(&lua->com); - if (!SET_SAFE_LJMP(lua->T)) + if (!SET_SAFE_LJMP(lua)) return; luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref); - RESET_SAFE_LJMP(lua->T); + RESET_SAFE_LJMP(lua); - if (!SET_SAFE_LJMP(lua->state_from)) + if (!SET_SAFE_LJMP_PARENT(lua)) return; luaL_unref(lua->state_from, LUA_REGISTRYINDEX, lua->Tref); - RESET_SAFE_LJMP(lua->state_from); + RESET_SAFE_LJMP_PARENT(lua); /* Forces a garbage collecting process. If the Lua program is finished * without error, we run the GC on the thread pointer. Its freed all * the unused memory. @@ -1071,10 +1086,10 @@ void hlua_ctx_destroy(struct hlua *lua) * the garbage collection. */ if (lua->gc_count) { - if (!SET_SAFE_LJMP(lua->state_from)) + if (!SET_SAFE_LJMP_PARENT(lua)) return; lua_gc(lua->state_from, LUA_GCCOLLECT, 0); - RESET_SAFE_LJMP(lua->state_from); + RESET_SAFE_LJMP_PARENT(lua); } lua->T = NULL; @@ -1201,7 +1216,8 @@ static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed) /* Lock the whole Lua execution. This lock must be before the * label "resume_execution". */ - HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock); + if (lua->state_from == gL.T) + HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock); resume_execution: @@ -1345,7 +1361,8 @@ resume_execution: } /* This is the main exit point, remove the Lua lock. */ - HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); + if (lua->state_from == gL.T) + HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); return ret; } @@ -6401,7 +6418,7 @@ static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, if (!HLUA_IS_RUNNING(stream->hlua)) { /* The following Lua calls can fail. */ - if (!SET_SAFE_LJMP(stream->hlua->T)) { + if (!SET_SAFE_LJMP(stream->hlua)) { if (lua_type(stream->hlua->T, -1) == LUA_TSTRING) error = lua_tostring(stream->hlua->T, -1); else @@ -6413,7 +6430,7 @@ static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, /* Check stack available size. */ if (!lua_checkstack(stream->hlua->T, 1)) { SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name); - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); return 0; } @@ -6423,7 +6440,7 @@ static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, /* convert input sample and pust-it in the stack. */ if (!lua_checkstack(stream->hlua->T, 1)) { SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name); - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); return 0; } hlua_smp2lua(stream->hlua->T, smp); @@ -6434,7 +6451,7 @@ static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, for (; arg_p->type != ARGT_STOP; arg_p++) { if (!lua_checkstack(stream->hlua->T, 1)) { SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name); - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); return 0; } hlua_arg2lua(stream->hlua->T, arg_p); @@ -6446,7 +6463,7 @@ static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, stream->hlua->max_time = hlua_timeout_session; /* At this point the execution is safe. */ - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); } /* Execute the function. */ @@ -6534,7 +6551,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp if (!HLUA_IS_RUNNING(stream->hlua)) { /* The following Lua calls can fail. */ - if (!SET_SAFE_LJMP(stream->hlua->T)) { + if (!SET_SAFE_LJMP(stream->hlua)) { if (lua_type(stream->hlua->T, -1) == LUA_TSTRING) error = lua_tostring(stream->hlua->T, -1); else @@ -6546,7 +6563,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp /* Check stack available size. */ if (!lua_checkstack(stream->hlua->T, 2)) { SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name); - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); return 0; } @@ -6556,7 +6573,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp /* push arguments in the stack. */ if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) { SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name); - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); return 0; } stream->hlua->nargs = 1; @@ -6566,7 +6583,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp /* Check stack available size. */ if (!lua_checkstack(stream->hlua->T, 1)) { SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name); - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); return 0; } hlua_arg2lua(stream->hlua->T, arg_p); @@ -6577,7 +6594,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp stream->hlua->max_time = hlua_timeout_session; /* At this point the execution is safe. */ - RESET_SAFE_LJMP(stream->hlua->T); + RESET_SAFE_LJMP(stream->hlua); } /* Execute the function. */ @@ -6837,7 +6854,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px, if (!HLUA_IS_RUNNING(s->hlua)) { /* The following Lua calls can fail. */ - if (!SET_SAFE_LJMP(s->hlua->T)) { + if (!SET_SAFE_LJMP(s->hlua)) { if (lua_type(s->hlua->T, -1) == LUA_TSTRING) error = lua_tostring(s->hlua->T, -1); else @@ -6851,7 +6868,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px, if (!lua_checkstack(s->hlua->T, 1)) { SEND_ERR(px, "Lua function '%s': full stack.\n", rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(s->hlua->T); + RESET_SAFE_LJMP(s->hlua); goto end; } @@ -6862,7 +6879,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px, if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) { SEND_ERR(px, "Lua function '%s': full stack.\n", rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(s->hlua->T); + RESET_SAFE_LJMP(s->hlua); goto end; } s->hlua->nargs = 1; @@ -6872,7 +6889,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px, if (!lua_checkstack(s->hlua->T, 1)) { SEND_ERR(px, "Lua function '%s': full stack.\n", rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(s->hlua->T); + RESET_SAFE_LJMP(s->hlua); goto end; } lua_pushstring(s->hlua->T, *arg); @@ -6880,7 +6897,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px, } /* Now the execution is safe. */ - RESET_SAFE_LJMP(s->hlua->T); + RESET_SAFE_LJMP(s->hlua); /* We must initialize the execution timeouts. */ s->hlua->max_time = hlua_timeout_session; @@ -7021,7 +7038,7 @@ static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct str hlua->max_time = ctx->applet->timeout; /* The following Lua calls can fail. */ - if (!SET_SAFE_LJMP(hlua->T)) { + if (!SET_SAFE_LJMP(hlua)) { if (lua_type(hlua->T, -1) == LUA_TSTRING) error = lua_tostring(hlua->T, -1); else @@ -7035,7 +7052,7 @@ static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct str if (!lua_checkstack(hlua->T, 1)) { SEND_ERR(px, "Lua applet tcp '%s': full stack.\n", ctx->rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); return 0; } @@ -7046,7 +7063,7 @@ static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct str if (!hlua_applet_tcp_new(hlua->T, ctx)) { SEND_ERR(px, "Lua applet tcp '%s': full stack.\n", ctx->rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); return 0; } hlua->nargs = 1; @@ -7056,14 +7073,14 @@ static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct str if (!lua_checkstack(hlua->T, 1)) { SEND_ERR(px, "Lua applet tcp '%s': full stack.\n", ctx->rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); return 0; } lua_pushstring(hlua->T, *arg); hlua->nargs++; } - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); /* Wakeup the applet ASAP. */ si_cant_get(si); @@ -7214,7 +7231,7 @@ static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct st hlua->max_time = ctx->applet->timeout; /* The following Lua calls can fail. */ - if (!SET_SAFE_LJMP(hlua->T)) { + if (!SET_SAFE_LJMP(hlua)) { if (lua_type(hlua->T, -1) == LUA_TSTRING) error = lua_tostring(hlua->T, -1); else @@ -7228,7 +7245,7 @@ static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct st if (!lua_checkstack(hlua->T, 1)) { SEND_ERR(px, "Lua applet http '%s': full stack.\n", ctx->rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); return 0; } @@ -7239,7 +7256,7 @@ static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct st if (!hlua_applet_http_new(hlua->T, ctx)) { SEND_ERR(px, "Lua applet http '%s': full stack.\n", ctx->rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); return 0; } hlua->nargs = 1; @@ -7249,14 +7266,14 @@ static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct st if (!lua_checkstack(hlua->T, 1)) { SEND_ERR(px, "Lua applet http '%s': full stack.\n", ctx->rule->arg.hlua_rule->fcn->name); - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); return 0; } lua_pushstring(hlua->T, *arg); hlua->nargs++; } - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); /* Wakeup the applet when data is ready for read. */ si_cant_get(si); @@ -7805,7 +7822,7 @@ static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, } /* The following Lua calls can fail. */ - if (!SET_SAFE_LJMP(hlua->T)) { + if (!SET_SAFE_LJMP(hlua)) { if (lua_type(hlua->T, -1) == LUA_TSTRING) error = lua_tostring(hlua->T, -1); else @@ -7847,14 +7864,14 @@ static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, hlua->max_time = hlua_timeout_session; /* At this point the execution is safe. */ - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); /* It's ok */ return 0; /* It's not ok. */ error: - RESET_SAFE_LJMP(hlua->T); + RESET_SAFE_LJMP(hlua); hlua_ctx_destroy(hlua); appctx->ctx.hlua_cli.hlua = NULL; return 1;