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.
diff --git a/src/hlua.c b/src/hlua.c
index 666aaf2..a3aa05b 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -438,6 +438,59 @@
 	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 @@
 	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:
+ *
+ *   <none> core.register_task(<function>)
+ */
+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 @@
 
 	/* 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);