1
0
Fork 0
knot-resolver/daemon/bindings/event.c
Daniel Baumann fbc604e215
Adding upstream version 5.7.5.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 13:56:17 +02:00

209 lines
5.3 KiB
C

/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "daemon/bindings/impl.h"
#include <unistd.h>
#include <uv.h>
static void event_free(uv_timer_t *timer)
{
lua_State *L = the_worker->engine->L;
int ref = (intptr_t) timer->data;
luaL_unref(L, LUA_REGISTRYINDEX, ref);
free(timer);
}
static void event_callback(uv_timer_t *timer)
{
lua_State *L = the_worker->engine->L;
/* Retrieve callback and execute */
lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t) timer->data);
lua_rawgeti(L, -1, 1);
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 && 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);
}
}
}
static void event_fdcallback(uv_poll_t* handle, int status, int events)
{
lua_State *L = the_worker->engine->L;
/* Retrieve callback and execute */
lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t) handle->data);
lua_rawgeti(L, -1, 1);
lua_pushinteger(L, (intptr_t) handle->data);
lua_pushinteger(L, status);
lua_pushinteger(L, events);
int ret = execute_callback(L, 3);
/* Free callback if not recurrent or an error */
if (ret != 0) {
if (!uv_is_closing((uv_handle_t *)handle)) {
uv_close((uv_handle_t *)handle, (uv_close_cb) event_free);
}
}
}
static int event_sched(lua_State *L, unsigned timeout, unsigned repeat)
{
uv_timer_t *timer = malloc(sizeof(*timer));
if (!timer)
lua_error_p(L, "out of memory");
/* Start timer with the reference */
uv_loop_t *loop = uv_default_loop();
uv_timer_init(loop, timer);
int ret = uv_timer_start(timer, event_callback, timeout, repeat);
if (ret != 0) {
free(timer);
lua_error_p(L, "couldn't start the event");
}
/* Save callback and timer in registry */
lua_newtable(L);
lua_pushvalue(L, 2);
lua_rawseti(L, -2, 1);
lua_pushpointer(L, timer);
lua_rawseti(L, -2, 2);
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
/* Save reference to the timer */
timer->data = (void *) (intptr_t)ref;
lua_pushinteger(L, ref);
return 1;
}
static int event_after(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2))
lua_error_p(L, "expected 'after(number timeout, function)'");
return event_sched(L, lua_tointeger(L, 1), 0);
}
static int event_recurrent(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 2 || !lua_isnumber(L, 1) || lua_tointeger(L, 1) == 0
|| !lua_isfunction(L, 2))
lua_error_p(L, "expected 'recurrent(number interval, function)'");
return event_sched(L, 0, lua_tointeger(L, 1));
}
static int event_cancel(lua_State *L)
{
int n = lua_gettop(L);
if (n < 1 || !lua_isnumber(L, 1))
lua_error_p(L, "expected 'cancel(number event)'");
/* Fetch event if it exists */
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, 1));
bool ok = lua_istable(L, -1);
/* Close the timer */
uv_handle_t **timer_pp = NULL;
if (ok) {
lua_rawgeti(L, -1, 2);
timer_pp = lua_touserdata(L, -1);
ok = timer_pp && *timer_pp;
/* That have been sufficient safety checks, hopefully. */
}
if (ok && !uv_is_closing(*timer_pp)) {
uv_close(*timer_pp, (uv_close_cb)event_free);
}
lua_pushboolean(L, ok);
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))
lua_error_p(L, "expected 'reschedule(number event, number timeout)'");
/* Fetch event if it exists */
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, 1));
bool ok = lua_istable(L, -1);
/* Reschedule the timer */
uv_handle_t **timer_pp = NULL;
if (ok) {
lua_rawgeti(L, -1, 2);
timer_pp = lua_touserdata(L, -1);
ok = timer_pp && *timer_pp;
/* That have been sufficient safety checks, hopefully. */
}
if (ok && !uv_is_closing(*timer_pp)) {
int ret = uv_timer_start((uv_timer_t *)*timer_pp,
event_callback, lua_tointeger(L, 2), 0);
if (ret != 0) {
uv_close(*timer_pp, (uv_close_cb)event_free);
ok = false;
}
}
lua_pushboolean(L, ok);
return 1;
}
static int event_fdwatch(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2))
lua_error_p(L, "expected 'socket(number fd, function)'");
uv_poll_t *handle = malloc(sizeof(*handle));
if (!handle)
lua_error_p(L, "out of memory");
/* Start timer with the reference */
int sock = lua_tointeger(L, 1);
uv_loop_t *loop = uv_default_loop();
int ret = uv_poll_init(loop, handle, sock);
if (ret == 0)
ret = uv_poll_start(handle, UV_READABLE, event_fdcallback);
if (ret != 0) {
free(handle);
lua_error_p(L, "couldn't start event poller");
}
/* Save callback and timer in registry */
lua_newtable(L);
lua_pushvalue(L, 2);
lua_rawseti(L, -2, 1);
lua_pushpointer(L, handle);
lua_rawseti(L, -2, 2);
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
/* Save reference to the timer */
handle->data = (void *) (intptr_t)ref;
lua_pushinteger(L, ref);
return 1;
}
int kr_bindings_event(lua_State *L)
{
static const luaL_Reg lib[] = {
{ "after", event_after },
{ "recurrent", event_recurrent },
{ "cancel", event_cancel },
{ "socket", event_fdwatch },
{ "reschedule", event_reschedule },
{ NULL, NULL }
};
luaL_register(L, "event", lib);
return 1;
}