From 3026afb79f648e5f38159127b290ae250d74fd95 Mon Sep 17 00:00:00 2001 From: Marek Vavrusa Date: Wed, 25 May 2016 17:14:52 -0700 Subject: [PATCH] daemon/bindings: event.reschedule(ev, timeout) this allows for efficient variable-interval running events, so that the timer doesn't have to be closed and recreated for each iteration --- daemon/README.rst | 18 ++++++++++++++++++ daemon/bindings.c | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/daemon/README.rst b/daemon/README.rst index 3e93b4e48..f4c640fbd 100644 --- a/daemon/README.rst +++ b/daemon/README.rst @@ -847,6 +847,24 @@ For example, ``5 * hour`` represents five hours, or 5*60*60*100 milliseconds. print('Hi #'..msg_count) end) +.. function:: event.reschedule(event_id, timeout) + + Reschedule a running event, it has no effect on canceled events. + New events may reuse the event_id, so the behaviour is undefined if the function + is called after another event is started. + + Example: + + .. code-block:: lua + + local interval = 1 * minute + event.after(1 * minute, function (ev) + print('Good morning!') + -- Halven the interval for each iteration + interval = interval / 2 + event.reschedule(ev, interval) + end) + .. function:: event.cancel(event_id) Cancel running event, it has no effect on already canceled events. diff --git a/daemon/bindings.c b/daemon/bindings.c index bc76147ac..28190a6f9 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -722,7 +722,7 @@ static void event_callback(uv_timer_t *timer) lua_pushinteger(L, (intptr_t) timer->data); int ret = execute_callback(L, 1); /* Free callback if not recurrent or an error */ - if (ret != 0 || uv_timer_get_repeat(timer) == 0) { + if (ret != 0 || (uv_timer_get_repeat(timer) == 0 && uv_is_active((uv_handle_t *)timer) == 0)) { if (!uv_is_closing((uv_handle_t *)timer)) { uv_close((uv_handle_t *)timer, (uv_close_cb) event_free); } @@ -829,6 +829,39 @@ static int event_cancel(lua_State *L) return 1; } +static int event_reschedule(lua_State *L) +{ + int n = lua_gettop(L); + if (n < 2 || !lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { + format_error(L, "expected 'reschedule(number event, number timeout)'"); + lua_error(L); + } + + /* Fetch event if it exists */ + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, 1)); + if (!lua_istable(L, -1)) { + lua_pushboolean(L, false); + return 1; + } + + /* Reschedule the timer */ + lua_rawgeti(L, -1, 2); + uv_handle_t *timer = lua_touserdata(L, -1); + if (!uv_is_closing(timer)) { + if (uv_is_active(timer)) { + uv_timer_stop((uv_timer_t *)timer); + } + int ret = uv_timer_start((uv_timer_t *)timer, event_callback, lua_tointeger(L, 2), 0); + if (ret != 0) { + event_cancel(L); + lua_pushboolean(L, false); + return 1; + } + } + lua_pushboolean(L, true); + return 1; +} + static int event_fdwatch(lua_State *L) { /* Check parameters */ @@ -892,6 +925,7 @@ int lib_event(lua_State *L) { "recurrent", event_recurrent }, { "cancel", event_cancel }, { "socket", event_fdwatch }, + { "reschedule", event_reschedule }, { NULL, NULL } }; -- 2.47.2