MINOR: hlua: use accessors for stream hlua ctx

Change hlua_stream_ctx_prepare() prototype so that it now returns the
proper hlua ctx on success instead of returning a boolean.

Add hlua_stream_ctx_get() to retrieve hlua ctx out of a given stream.

This way we may easily change the storage mechanism for hlua stream in
the future without extensive code changes.

No backport needed unless a commit depends on it.
This commit is contained in:
Aurelien DARRAGON 2024-03-12 17:00:25 +01:00
parent 1a2cdf64c9
commit aa554be69c

View File

@ -1678,6 +1678,57 @@ static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
return 1; return 1;
} }
/* Helper function to get the lua ctx for a given stream */
static inline struct hlua *hlua_stream_ctx_get(struct stream *s)
{
return s->hlua;
}
/* Helper function to prepare the lua ctx for a given stream
*
* ctx will be enforced in <state_id> parent stack on initial creation.
* If s->hlua->state_id differs from <state_id>, which may happen at
* runtime since existing stream hlua ctx will be reused for other
* "independent" (but stream-related) lua executions, hlua will be
* recreated with the expected state id.
*
* Returns hlua ctx on success and NULL on failure
*/
static struct hlua *hlua_stream_ctx_prepare(struct stream *s, int state_id)
{
/* In the execution wrappers linked with a stream, the
* Lua context can be not initialized. This behavior
* permits to save performances because a systematic
* Lua initialization cause 5% performances loss.
*/
ctx_renew:
if (!s->hlua) {
struct hlua *hlua;
hlua = pool_alloc(pool_head_hlua);
if (!hlua)
return NULL;
HLUA_INIT(hlua);
if (!hlua_ctx_init(hlua, state_id, s->task)) {
pool_free(pool_head_hlua, hlua);
return NULL;
}
s->hlua = hlua;
}
else if (s->hlua->state_id != state_id) {
/* ctx already created, but not in proper state.
* It should only happen after the previous execution is
* finished, otherwise it's probably a bug since we don't
* want to abort unfinished job..
*/
BUG_ON(HLUA_IS_RUNNING(s->hlua));
hlua_ctx_destroy(s->hlua);
s->hlua = NULL;
goto ctx_renew;
}
return s->hlua;
}
void hlua_hook(lua_State *L, lua_Debug *ar) void hlua_hook(lua_State *L, lua_Debug *ar)
{ {
struct hlua *hlua; struct hlua *hlua;
@ -4946,12 +4997,11 @@ __LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
{ {
struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1)); struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
struct stream *s = luactx->htxn.s; struct stream *s = luactx->htxn.s;
struct hlua *hlua; struct hlua *hlua = hlua_stream_ctx_get(s);
/* Note that this hlua struct is from the session and not from the applet. */ /* Note that this hlua struct is from the session and not from the applet. */
if (!s->hlua) if (!hlua)
return 0; return 0;
hlua = s->hlua;
MAY_LJMP(check_args(L, 2, "set_priv")); MAY_LJMP(check_args(L, 2, "set_priv"));
@ -4969,14 +5019,13 @@ __LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
{ {
struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1)); struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
struct stream *s = luactx->htxn.s; struct stream *s = luactx->htxn.s;
struct hlua *hlua; struct hlua *hlua = hlua_stream_ctx_get(s);
/* Note that this hlua struct is from the session and not from the applet. */ /* Note that this hlua struct is from the session and not from the applet. */
if (!s->hlua) { if (!hlua) {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }
hlua = s->hlua;
/* Push configuration index in the stack. */ /* Push configuration index in the stack. */
lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref); lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
@ -5437,12 +5486,11 @@ __LJMP static int hlua_applet_http_set_priv(lua_State *L)
{ {
struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1)); struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
struct stream *s = luactx->htxn.s; struct stream *s = luactx->htxn.s;
struct hlua *hlua; struct hlua *hlua = hlua_stream_ctx_get(s);
/* Note that this hlua struct is from the session and not from the applet. */ /* Note that this hlua struct is from the session and not from the applet. */
if (!s->hlua) if (!hlua)
return 0; return 0;
hlua = s->hlua;
MAY_LJMP(check_args(L, 2, "set_priv")); MAY_LJMP(check_args(L, 2, "set_priv"));
@ -5460,14 +5508,13 @@ __LJMP static int hlua_applet_http_get_priv(lua_State *L)
{ {
struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1)); struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
struct stream *s = luactx->htxn.s; struct stream *s = luactx->htxn.s;
struct hlua *hlua; struct hlua *hlua = hlua_stream_ctx_get(s);
/* Note that this hlua struct is from the session and not from the applet. */ /* Note that this hlua struct is from the session and not from the applet. */
if (!s->hlua) { if (!hlua) {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }
hlua = s->hlua;
/* Push configuration index in the stack. */ /* Push configuration index in the stack. */
lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref); lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
@ -9056,51 +9103,6 @@ struct task *hlua_process_task(struct task *task, void *context, unsigned int st
return task; return task;
} }
/* Helper function to prepare the lua ctx for a given stream
*
* ctx will be enforced in <state_id> parent stack on initial creation.
* If s->hlua->state_id differs from <state_id>, which may happen at
* runtime since existing stream hlua ctx will be reused for other
* "independent" (but stream-related) lua executions, hlua will be
* recreated with the expected state id.
*
* Returns 1 for success and 0 for failure
*/
static int hlua_stream_ctx_prepare(struct stream *s, int state_id)
{
/* In the execution wrappers linked with a stream, the
* Lua context can be not initialized. This behavior
* permits to save performances because a systematic
* Lua initialization cause 5% performances loss.
*/
ctx_renew:
if (!s->hlua) {
struct hlua *hlua;
hlua = pool_alloc(pool_head_hlua);
if (!hlua)
return 0;
HLUA_INIT(hlua);
if (!hlua_ctx_init(hlua, state_id, s->task)) {
pool_free(pool_head_hlua, hlua);
return 0;
}
s->hlua = hlua;
}
else if (s->hlua->state_id != state_id) {
/* ctx already created, but not in proper state.
* It should only happen after the previous execution is
* finished, otherwise it's probably a bug since we don't
* want to abort unfinished job..
*/
BUG_ON(HLUA_IS_RUNNING(s->hlua));
hlua_ctx_destroy(s->hlua);
s->hlua = NULL;
goto ctx_renew;
}
return 1;
}
/* This function is an LUA binding that register LUA function to be /* This function is an LUA binding that register LUA function to be
* executed after the HAProxy configuration parsing and before the * executed after the HAProxy configuration parsing and before the
* HAProxy scheduler starts. This function expect only one LUA * HAProxy scheduler starts. This function expect only one LUA
@ -9937,89 +9939,90 @@ static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp,
{ {
struct hlua_function *fcn = private; struct hlua_function *fcn = private;
struct stream *stream = smp->strm; struct stream *stream = smp->strm;
struct hlua *hlua = NULL;
const char *error; const char *error;
if (!stream) if (!stream)
return 0; return 0;
if (!hlua_stream_ctx_prepare(stream, fcn_ref_to_stack_id(fcn))) { if (!(hlua = hlua_stream_ctx_prepare(stream, fcn_ref_to_stack_id(fcn)))) {
SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name); SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
return 0; return 0;
} }
/* If it is the first run, initialize the data for the call. */ /* If it is the first run, initialize the data for the call. */
if (!HLUA_IS_RUNNING(stream->hlua)) { if (!HLUA_IS_RUNNING(hlua)) {
/* The following Lua calls can fail. */ /* The following Lua calls can fail. */
if (!SET_SAFE_LJMP(stream->hlua)) { if (!SET_SAFE_LJMP(hlua)) {
hlua_lock(stream->hlua); hlua_lock(hlua);
if (lua_type(stream->hlua->T, -1) == LUA_TSTRING) if (lua_type(hlua->T, -1) == LUA_TSTRING)
error = hlua_tostring_safe(stream->hlua->T, -1); error = hlua_tostring_safe(hlua->T, -1);
else else
error = "critical error"; error = "critical error";
SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error); SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
hlua_unlock(stream->hlua); hlua_unlock(hlua);
return 0; return 0;
} }
/* Check stack available size. */ /* Check stack available size. */
if (!lua_checkstack(stream->hlua->T, 1)) { if (!lua_checkstack(hlua->T, 1)) {
SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name); SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
return 0; return 0;
} }
/* Restore the function in the stack. */ /* Restore the function in the stack. */
hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]); hlua_pushref(hlua->T, fcn->function_ref[hlua->state_id]);
/* convert input sample and pust-it in the stack. */ /* convert input sample and pust-it in the stack. */
if (!lua_checkstack(stream->hlua->T, 1)) { if (!lua_checkstack(hlua->T, 1)) {
SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name); SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
return 0; return 0;
} }
MAY_LJMP(hlua_smp2lua(stream->hlua->T, smp)); MAY_LJMP(hlua_smp2lua(hlua->T, smp));
stream->hlua->nargs = 1; hlua->nargs = 1;
/* push keywords in the stack. */ /* push keywords in the stack. */
if (arg_p) { if (arg_p) {
for (; arg_p->type != ARGT_STOP; arg_p++) { for (; arg_p->type != ARGT_STOP; arg_p++) {
if (!lua_checkstack(stream->hlua->T, 1)) { if (!lua_checkstack(hlua->T, 1)) {
SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name); SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
return 0; return 0;
} }
MAY_LJMP(hlua_arg2lua(stream->hlua->T, arg_p)); MAY_LJMP(hlua_arg2lua(hlua->T, arg_p));
stream->hlua->nargs++; hlua->nargs++;
} }
} }
/* We must initialize the execution timeouts. */ /* We must initialize the execution timeouts. */
hlua_timer_init(&stream->hlua->timer, hlua_timeout_session); hlua_timer_init(&hlua->timer, hlua_timeout_session);
/* At this point the execution is safe. */ /* At this point the execution is safe. */
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
} }
/* Execute the function. */ /* Execute the function. */
switch (hlua_ctx_resume(stream->hlua, 0)) { switch (hlua_ctx_resume(hlua, 0)) {
/* finished. */ /* finished. */
case HLUA_E_OK: case HLUA_E_OK:
hlua_lock(stream->hlua); hlua_lock(hlua);
/* If the stack is empty, the function fails. */ /* If the stack is empty, the function fails. */
if (lua_gettop(stream->hlua->T) <= 0) { if (lua_gettop(hlua->T) <= 0) {
hlua_unlock(stream->hlua); hlua_unlock(hlua);
return 0; return 0;
} }
/* Convert the returned value in sample. */ /* Convert the returned value in sample. */
hlua_lua2smp(stream->hlua->T, -1, smp); hlua_lua2smp(hlua->T, -1, smp);
/* dup the smp before popping the related lua value and /* dup the smp before popping the related lua value and
* returning it to haproxy * returning it to haproxy
*/ */
smp_dup(smp); smp_dup(smp);
lua_pop(stream->hlua->T, 1); lua_pop(hlua->T, 1);
hlua_unlock(stream->hlua); hlua_unlock(hlua);
return 1; return 1;
/* yield. */ /* yield. */
@ -10030,11 +10033,11 @@ static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp,
/* finished with error. */ /* finished with error. */
case HLUA_E_ERRMSG: case HLUA_E_ERRMSG:
/* Display log. */ /* Display log. */
hlua_lock(stream->hlua); hlua_lock(hlua);
SEND_ERR(stream->be, "Lua converter '%s': %s.\n", SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
fcn->name, hlua_tostring_safe(stream->hlua->T, -1)); fcn->name, hlua_tostring_safe(hlua->T, -1));
lua_pop(stream->hlua->T, 1); lua_pop(hlua->T, 1);
hlua_unlock(stream->hlua); hlua_unlock(hlua);
return 0; return 0;
case HLUA_E_ETMOUT: case HLUA_E_ETMOUT:
@ -10069,88 +10072,89 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
{ {
struct hlua_function *fcn = private; struct hlua_function *fcn = private;
struct stream *stream = smp->strm; struct stream *stream = smp->strm;
struct hlua *hlua = NULL;
const char *error; const char *error;
unsigned int hflags = HLUA_TXN_NOTERM | HLUA_TXN_SMP_CTX; unsigned int hflags = HLUA_TXN_NOTERM | HLUA_TXN_SMP_CTX;
if (!stream) if (!stream)
return 0; return 0;
if (!hlua_stream_ctx_prepare(stream, fcn_ref_to_stack_id(fcn))) { if (!(hlua = hlua_stream_ctx_prepare(stream, fcn_ref_to_stack_id(fcn)))) {
SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name); SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
return 0; return 0;
} }
/* If it is the first run, initialize the data for the call. */ /* If it is the first run, initialize the data for the call. */
if (!HLUA_IS_RUNNING(stream->hlua)) { if (!HLUA_IS_RUNNING(hlua)) {
/* The following Lua calls can fail. */ /* The following Lua calls can fail. */
if (!SET_SAFE_LJMP(stream->hlua)) { if (!SET_SAFE_LJMP(hlua)) {
hlua_lock(stream->hlua); hlua_lock(hlua);
if (lua_type(stream->hlua->T, -1) == LUA_TSTRING) if (lua_type(hlua->T, -1) == LUA_TSTRING)
error = hlua_tostring_safe(stream->hlua->T, -1); error = hlua_tostring_safe(hlua->T, -1);
else else
error = "critical error"; error = "critical error";
SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error); SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
hlua_unlock(stream->hlua); hlua_unlock(hlua);
return 0; return 0;
} }
/* Check stack available size. */ /* Check stack available size. */
if (!lua_checkstack(stream->hlua->T, 2)) { if (!lua_checkstack(hlua->T, 2)) {
SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name); SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
return 0; return 0;
} }
/* Restore the function in the stack. */ /* Restore the function in the stack. */
hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]); hlua_pushref(hlua->T, fcn->function_ref[hlua->state_id]);
/* push arguments in the stack. */ /* push arguments in the stack. */
if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) { if (!hlua_txn_new(hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name); SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
return 0; return 0;
} }
stream->hlua->nargs = 1; hlua->nargs = 1;
/* push keywords in the stack. */ /* push keywords in the stack. */
for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) { for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
/* Check stack available size. */ /* Check stack available size. */
if (!lua_checkstack(stream->hlua->T, 1)) { if (!lua_checkstack(hlua->T, 1)) {
SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name); SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
return 0; return 0;
} }
MAY_LJMP(hlua_arg2lua(stream->hlua->T, arg_p)); MAY_LJMP(hlua_arg2lua(hlua->T, arg_p));
stream->hlua->nargs++; hlua->nargs++;
} }
/* We must initialize the execution timeouts. */ /* We must initialize the execution timeouts. */
hlua_timer_init(&stream->hlua->timer, hlua_timeout_session); hlua_timer_init(&hlua->timer, hlua_timeout_session);
/* At this point the execution is safe. */ /* At this point the execution is safe. */
RESET_SAFE_LJMP(stream->hlua); RESET_SAFE_LJMP(hlua);
} }
/* Execute the function. */ /* Execute the function. */
switch (hlua_ctx_resume(stream->hlua, 0)) { switch (hlua_ctx_resume(hlua, 0)) {
/* finished. */ /* finished. */
case HLUA_E_OK: case HLUA_E_OK:
hlua_lock(stream->hlua); hlua_lock(hlua);
/* If the stack is empty, the function fails. */ /* If the stack is empty, the function fails. */
if (lua_gettop(stream->hlua->T) <= 0) { if (lua_gettop(hlua->T) <= 0) {
hlua_unlock(stream->hlua); hlua_unlock(hlua);
return 0; return 0;
} }
/* Convert the returned value in sample. */ /* Convert the returned value in sample. */
hlua_lua2smp(stream->hlua->T, -1, smp); hlua_lua2smp(hlua->T, -1, smp);
/* dup the smp before popping the related lua value and /* dup the smp before popping the related lua value and
* returning it to haproxy * returning it to haproxy
*/ */
smp_dup(smp); smp_dup(smp);
lua_pop(stream->hlua->T, 1); lua_pop(hlua->T, 1);
hlua_unlock(stream->hlua); hlua_unlock(hlua);
/* Set the end of execution flag. */ /* Set the end of execution flag. */
smp->flags &= ~SMP_F_MAY_CHANGE; smp->flags &= ~SMP_F_MAY_CHANGE;
@ -10164,11 +10168,11 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
/* finished with error. */ /* finished with error. */
case HLUA_E_ERRMSG: case HLUA_E_ERRMSG:
/* Display log. */ /* Display log. */
hlua_lock(stream->hlua); hlua_lock(hlua);
SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
fcn->name, hlua_tostring_safe(stream->hlua->T, -1)); fcn->name, hlua_tostring_safe(hlua->T, -1));
lua_pop(stream->hlua->T, 1); lua_pop(hlua->T, 1);
hlua_unlock(stream->hlua); hlua_unlock(hlua);
return 0; return 0;
case HLUA_E_ETMOUT: case HLUA_E_ETMOUT:
@ -10401,6 +10405,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
unsigned int hflags = HLUA_TXN_ACT_CTX; unsigned int hflags = HLUA_TXN_ACT_CTX;
int dir, act_ret = ACT_RET_CONT; int dir, act_ret = ACT_RET_CONT;
const char *error; const char *error;
struct hlua *hlua = NULL;
switch (rule->from) { switch (rule->from) {
case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break; case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
@ -10412,76 +10417,76 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
goto end; goto end;
} }
if (!hlua_stream_ctx_prepare(s, fcn_ref_to_stack_id(rule->arg.hlua_rule->fcn))) { if (!(hlua = hlua_stream_ctx_prepare(s, fcn_ref_to_stack_id(rule->arg.hlua_rule->fcn)))) {
SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n", SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
rule->arg.hlua_rule->fcn->name); rule->arg.hlua_rule->fcn->name);
goto end; goto end;
} }
/* If it is the first run, initialize the data for the call. */ /* If it is the first run, initialize the data for the call. */
if (!HLUA_IS_RUNNING(s->hlua)) { if (!HLUA_IS_RUNNING(hlua)) {
/* The following Lua calls can fail. */ /* The following Lua calls can fail. */
if (!SET_SAFE_LJMP(s->hlua)) { if (!SET_SAFE_LJMP(hlua)) {
hlua_lock(s->hlua); hlua_lock(hlua);
if (lua_type(s->hlua->T, -1) == LUA_TSTRING) if (lua_type(hlua->T, -1) == LUA_TSTRING)
error = hlua_tostring_safe(s->hlua->T, -1); error = hlua_tostring_safe(hlua->T, -1);
else else
error = "critical error"; error = "critical error";
SEND_ERR(px, "Lua function '%s': %s.\n", SEND_ERR(px, "Lua function '%s': %s.\n",
rule->arg.hlua_rule->fcn->name, error); rule->arg.hlua_rule->fcn->name, error);
hlua_unlock(s->hlua); hlua_unlock(hlua);
goto end; goto end;
} }
/* Check stack available size. */ /* Check stack available size. */
if (!lua_checkstack(s->hlua->T, 1)) { if (!lua_checkstack(hlua->T, 1)) {
SEND_ERR(px, "Lua function '%s': full stack.\n", SEND_ERR(px, "Lua function '%s': full stack.\n",
rule->arg.hlua_rule->fcn->name); rule->arg.hlua_rule->fcn->name);
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
goto end; goto end;
} }
/* Restore the function in the stack. */ /* Restore the function in the stack. */
hlua_pushref(s->hlua->T, rule->arg.hlua_rule->fcn->function_ref[s->hlua->state_id]); hlua_pushref(hlua->T, rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
/* Create and and push object stream in the stack. */ /* Create and and push object stream in the stack. */
if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) { if (!hlua_txn_new(hlua->T, s, px, dir, hflags)) {
SEND_ERR(px, "Lua function '%s': full stack.\n", SEND_ERR(px, "Lua function '%s': full stack.\n",
rule->arg.hlua_rule->fcn->name); rule->arg.hlua_rule->fcn->name);
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
goto end; goto end;
} }
s->hlua->nargs = 1; hlua->nargs = 1;
/* push keywords in the stack. */ /* push keywords in the stack. */
for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) { for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
if (!lua_checkstack(s->hlua->T, 1)) { if (!lua_checkstack(hlua->T, 1)) {
SEND_ERR(px, "Lua function '%s': full stack.\n", SEND_ERR(px, "Lua function '%s': full stack.\n",
rule->arg.hlua_rule->fcn->name); rule->arg.hlua_rule->fcn->name);
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
goto end; goto end;
} }
lua_pushstring(s->hlua->T, *arg); lua_pushstring(hlua->T, *arg);
s->hlua->nargs++; hlua->nargs++;
} }
/* Now the execution is safe. */ /* Now the execution is safe. */
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
/* We must initialize the execution timeouts. */ /* We must initialize the execution timeouts. */
hlua_timer_init(&s->hlua->timer, hlua_timeout_session); hlua_timer_init(&hlua->timer, hlua_timeout_session);
} }
/* Execute the function. */ /* Execute the function. */
switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) { switch (hlua_ctx_resume(hlua, !(flags & ACT_OPT_FINAL))) {
/* finished. */ /* finished. */
case HLUA_E_OK: case HLUA_E_OK:
/* Catch the return value */ /* Catch the return value */
hlua_lock(s->hlua); hlua_lock(hlua);
if (lua_gettop(s->hlua->T) > 0) if (lua_gettop(hlua->T) > 0)
act_ret = lua_tointeger(s->hlua->T, -1); act_ret = lua_tointeger(hlua->T, -1);
hlua_unlock(s->hlua); hlua_unlock(hlua);
/* Set timeout in the required channel. */ /* Set timeout in the required channel. */
if (act_ret == ACT_RET_YIELD) { if (act_ret == ACT_RET_YIELD) {
@ -10490,10 +10495,10 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
if (dir == SMP_OPT_DIR_REQ) if (dir == SMP_OPT_DIR_REQ)
s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp), s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
s->hlua->wake_time); hlua->wake_time);
else else
s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp), s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
s->hlua->wake_time); hlua->wake_time);
} }
goto end; goto end;
@ -10502,18 +10507,18 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
/* Set timeout in the required channel. */ /* Set timeout in the required channel. */
if (dir == SMP_OPT_DIR_REQ) if (dir == SMP_OPT_DIR_REQ)
s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp), s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
s->hlua->wake_time); hlua->wake_time);
else else
s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp), s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
s->hlua->wake_time); hlua->wake_time);
/* Some actions can be wake up when a "write" event /* Some actions can be wake up when a "write" event
* is detected on a response channel. This is useful * is detected on a response channel. This is useful
* only for actions targeted on the requests. * only for actions targeted on the requests.
*/ */
if (HLUA_IS_WAKERESWR(s->hlua)) if (HLUA_IS_WAKERESWR(hlua))
s->res.flags |= CF_WAKE_WRITE; s->res.flags |= CF_WAKE_WRITE;
if (HLUA_IS_WAKEREQWR(s->hlua)) if (HLUA_IS_WAKEREQWR(hlua))
s->req.flags |= CF_WAKE_WRITE; s->req.flags |= CF_WAKE_WRITE;
act_ret = ACT_RET_YIELD; act_ret = ACT_RET_YIELD;
goto end; goto end;
@ -10521,11 +10526,11 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
/* finished with error. */ /* finished with error. */
case HLUA_E_ERRMSG: case HLUA_E_ERRMSG:
/* Display log. */ /* Display log. */
hlua_lock(s->hlua); hlua_lock(hlua);
SEND_ERR(px, "Lua function '%s': %s.\n", SEND_ERR(px, "Lua function '%s': %s.\n",
rule->arg.hlua_rule->fcn->name, hlua_tostring_safe(s->hlua->T, -1)); rule->arg.hlua_rule->fcn->name, hlua_tostring_safe(hlua->T, -1));
lua_pop(s->hlua->T, 1); lua_pop(hlua->T, 1);
hlua_unlock(s->hlua); hlua_unlock(hlua);
goto end; goto end;
case HLUA_E_ETMOUT: case HLUA_E_ETMOUT:
@ -10553,8 +10558,8 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
} }
end: end:
if (act_ret != ACT_RET_YIELD && s->hlua) if (act_ret != ACT_RET_YIELD && hlua)
s->hlua->wake_time = TICK_ETERNITY; hlua->wake_time = TICK_ETERNITY;
return act_ret; return act_ret;
} }
@ -11874,9 +11879,10 @@ static int hlua_filter_new(struct stream *s, struct filter *filter)
{ {
struct hlua_flt_config *conf = FLT_CONF(filter); struct hlua_flt_config *conf = FLT_CONF(filter);
struct hlua_flt_ctx *flt_ctx = NULL; struct hlua_flt_ctx *flt_ctx = NULL;
struct hlua *hlua = NULL;
int ret = 1; int ret = 1;
if (!hlua_stream_ctx_prepare(s, reg_flt_to_stack_id(conf->reg))) { if (!(hlua = hlua_stream_ctx_prepare(s, reg_flt_to_stack_id(conf->reg)))) {
SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n", SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
conf->reg->name); conf->reg->name);
ret = 0; ret = 0;
@ -11910,92 +11916,92 @@ static int hlua_filter_new(struct stream *s, struct filter *filter)
goto end; goto end;
} }
if (!HLUA_IS_RUNNING(s->hlua)) { if (!HLUA_IS_RUNNING(hlua)) {
/* The following Lua calls can fail. */ /* The following Lua calls can fail. */
if (!SET_SAFE_LJMP(s->hlua)) { if (!SET_SAFE_LJMP(hlua)) {
const char *error; const char *error;
hlua_lock(s->hlua); hlua_lock(hlua);
if (lua_type(s->hlua->T, -1) == LUA_TSTRING) if (lua_type(hlua->T, -1) == LUA_TSTRING)
error = hlua_tostring_safe(s->hlua->T, -1); error = hlua_tostring_safe(hlua->T, -1);
else else
error = "critical error"; error = "critical error";
SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error); SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
hlua_unlock(s->hlua); hlua_unlock(hlua);
ret = 0; ret = 0;
goto end; goto end;
} }
/* Check stack size. */ /* Check stack size. */
if (!lua_checkstack(s->hlua->T, 1)) { if (!lua_checkstack(hlua->T, 1)) {
SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name); SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
ret = 0; ret = 0;
goto end; goto end;
} }
hlua_pushref(s->hlua->T, conf->ref[s->hlua->state_id]); hlua_pushref(hlua->T, conf->ref[hlua->state_id]);
if (lua_getfield(s->hlua->T, -1, "new") != LUA_TFUNCTION) { if (lua_getfield(hlua->T, -1, "new") != LUA_TFUNCTION) {
SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n", SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n",
conf->reg->name); conf->reg->name);
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
ret = 0; ret = 0;
goto end; goto end;
} }
lua_insert(s->hlua->T, -2); lua_insert(hlua->T, -2);
/* Push the copy on the stack */ /* Push the copy on the stack */
s->hlua->nargs = 1; hlua->nargs = 1;
/* We must initialize the execution timeouts. */ /* We must initialize the execution timeouts. */
hlua_timer_init(&s->hlua->timer, hlua_timeout_session); hlua_timer_init(&hlua->timer, hlua_timeout_session);
/* At this point the execution is safe. */ /* At this point the execution is safe. */
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
} }
switch (hlua_ctx_resume(s->hlua, 0)) { switch (hlua_ctx_resume(hlua, 0)) {
case HLUA_E_OK: case HLUA_E_OK:
/* The following Lua calls can fail. */ /* The following Lua calls can fail. */
if (!SET_SAFE_LJMP(s->hlua)) { if (!SET_SAFE_LJMP(hlua)) {
const char *error; const char *error;
hlua_lock(s->hlua); hlua_lock(hlua);
if (lua_type(s->hlua->T, -1) == LUA_TSTRING) if (lua_type(hlua->T, -1) == LUA_TSTRING)
error = hlua_tostring_safe(s->hlua->T, -1); error = hlua_tostring_safe(hlua->T, -1);
else else
error = "critical error"; error = "critical error";
SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error); SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
hlua_unlock(s->hlua); hlua_unlock(hlua);
ret = 0; ret = 0;
goto end; goto end;
} }
/* Nothing returned or not a table, ignore the filter for current stream */ /* Nothing returned or not a table, ignore the filter for current stream */
if (!lua_gettop(s->hlua->T) || !lua_istable(s->hlua->T, 1)) { if (!lua_gettop(hlua->T) || !lua_istable(hlua->T, 1)) {
ret = 0; ret = 0;
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
goto end; goto end;
} }
/* Attached the filter pointer to the ctx */ /* Attached the filter pointer to the ctx */
lua_pushstring(s->hlua->T, "__filter"); lua_pushstring(hlua->T, "__filter");
lua_pushlightuserdata(s->hlua->T, filter); lua_pushlightuserdata(hlua->T, filter);
lua_settable(s->hlua->T, -3); lua_settable(hlua->T, -3);
/* Save a ref on the filter ctx */ /* Save a ref on the filter ctx */
lua_pushvalue(s->hlua->T, 1); lua_pushvalue(hlua->T, 1);
flt_ctx->ref = hlua_ref(s->hlua->T); flt_ctx->ref = hlua_ref(hlua->T);
/* At this point the execution is safe. */ /* At this point the execution is safe. */
RESET_SAFE_LJMP(s->hlua); RESET_SAFE_LJMP(hlua);
filter->ctx = flt_ctx; filter->ctx = flt_ctx;
break; break;
case HLUA_E_ERRMSG: case HLUA_E_ERRMSG:
hlua_lock(s->hlua); hlua_lock(hlua);
SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, hlua_tostring_safe(s->hlua->T, -1)); SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, hlua_tostring_safe(hlua->T, -1));
hlua_unlock(s->hlua); hlua_unlock(hlua);
ret = -1; ret = -1;
goto end; goto end;
case HLUA_E_ETMOUT: case HLUA_E_ETMOUT:
@ -12022,10 +12028,10 @@ static int hlua_filter_new(struct stream *s, struct filter *filter)
} }
end: end:
if (s->hlua) { if (hlua) {
hlua_lock(s->hlua); hlua_lock(hlua);
lua_settop(s->hlua->T, 0); lua_settop(hlua->T, 0);
hlua_unlock(s->hlua); hlua_unlock(hlua);
} }
if (ret <= 0) { if (ret <= 0) {
if (flt_ctx) { if (flt_ctx) {
@ -12040,10 +12046,11 @@ static int hlua_filter_new(struct stream *s, struct filter *filter)
static void hlua_filter_delete(struct stream *s, struct filter *filter) static void hlua_filter_delete(struct stream *s, struct filter *filter)
{ {
struct hlua_flt_ctx *flt_ctx = filter->ctx; struct hlua_flt_ctx *flt_ctx = filter->ctx;
struct hlua *hlua = hlua_stream_ctx_get(s);
hlua_lock(s->hlua); hlua_lock(hlua);
hlua_unref(s->hlua->T, flt_ctx->ref); hlua_unref(hlua->T, flt_ctx->ref);
hlua_unlock(s->hlua); hlua_unlock(hlua);
hlua_ctx_destroy(flt_ctx->hlua[0]); hlua_ctx_destroy(flt_ctx->hlua[0]);
hlua_ctx_destroy(flt_ctx->hlua[1]); hlua_ctx_destroy(flt_ctx->hlua[1]);
pool_free(pool_head_hlua_flt_ctx, flt_ctx); pool_free(pool_head_hlua_flt_ctx, flt_ctx);