From 24f3353403e0debacee8a2bb90df1fbb8b6cf4e2 Mon Sep 17 00:00:00 2001 From: Thierry FOURNIER Date: Fri, 23 Jan 2015 12:13:00 +0100 Subject: [PATCH] MEDIUM: lua: add coroutine as tasks. This LUA subsystem permits to execute LUA code in parallel of the main HAProxy activity. This is useful for periodic updates or special checks. --- src/hlua.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/hlua.c b/src/hlua.c index 666aaf225..a3aa05b74 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -438,6 +438,59 @@ static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed) return ret; } +/* This function is used as a calback of a task. It is called by the + * HAProxy task subsystem when the task is awaked. The LUA runtime can + * return an E_AGAIN signal, the emmiter of this signal must set a + * signal to wake the task. + */ +static struct task *hlua_process_task(struct task *task) +{ + struct hlua *hlua = task->context; + enum hlua_exec status; + + /* We need to remove the task from the wait queue before executing + * the Lua code because we don't know if it needs to wait for + * another timer or not in the case of E_AGAIN. + */ + task_delete(task); + + /* Execute the Lua code. */ + status = hlua_ctx_resume(hlua, 1); + + switch (status) { + /* finished or yield */ + case HLUA_E_OK: + hlua_ctx_destroy(hlua); + task_delete(task); + task_free(task); + break; + + case HLUA_E_AGAIN: /* co process wake me later. */ + break; + + /* finished with error. */ + case HLUA_E_ERRMSG: + send_log(NULL, LOG_ERR, "Lua task: %s.", lua_tostring(hlua->T, -1)); + if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) + Alert("Lua task: %s.\n", lua_tostring(hlua->T, -1)); + hlua_ctx_destroy(hlua); + task_delete(task); + task_free(task); + break; + + case HLUA_E_ERR: + default: + send_log(NULL, LOG_ERR, "Lua task: unknown error."); + if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) + Alert("Lua task: unknown error.\n"); + hlua_ctx_destroy(hlua); + task_delete(task); + task_free(task); + break; + } + return NULL; +} + /* This function is an LUA binding that register LUA function to be * executed after the HAProxy configuration parsing and before the * HAProxy scheduler starts. This function expect only one LUA @@ -462,6 +515,46 @@ __LJMP static int hlua_register_init(lua_State *L) return 0; } +/* This functio is an LUA binding. It permits to register a task + * executed in parallel of the main HAroxy activity. The task is + * created and it is set in the HAProxy scheduler. It can be called + * from the "init" section, "post init" or during the runtime. + * + * Lua prototype: + * + * core.register_task() + */ +static int hlua_register_task(lua_State *L) +{ + struct hlua *hlua; + struct task *task; + int ref; + + MAY_LJMP(check_args(L, 1, "register_task")); + + ref = MAY_LJMP(hlua_checkfunction(L, 1)); + + hlua = malloc(sizeof(*hlua)); + if (!hlua) + WILL_LJMP(luaL_error(L, "lua out of memory error.")); + + task = task_new(); + task->context = hlua; + task->process = hlua_process_task; + + if (!hlua_ctx_init(hlua, task)) + WILL_LJMP(luaL_error(L, "lua out of memory error.")); + + /* Restore the function in the stack. */ + lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ref); + hlua->nargs = 0; + + /* Schedule task. */ + task_schedule(task, now_ms); + + return 0; +} + /* This function is called by the main configuration key "lua-load". It loads and * execute an lua file during the parsing of the HAProxy configuration file. It is * the main lua entry point. @@ -594,6 +687,7 @@ void hlua_init(void) /* Register special functions. */ hlua_class_function(gL.T, "register_init", hlua_register_init); + hlua_class_function(gL.T, "register_task", hlua_register_task); /* Store the table __index in the metable. */ lua_settable(gL.T, -3);