util.signal: Wrap signalfd in an userdatum for gc handling etc
authorKim Alvefur <zash@zash.se>
Sat, 24 Feb 2024 01:00:44 +0100
changeset 13445 6d96b6eeee5a
parent 13444 b27de3d2bad6
child 13446 eb0fab7e5d32
util.signal: Wrap signalfd in an userdatum for gc handling etc
net/server_epoll.lua
util-src/signal.c
--- a/net/server_epoll.lua	Sat Feb 24 00:20:35 2024 +0100
+++ b/net/server_epoll.lua	Sat Feb 24 01:00:44 2024 +0100
@@ -1147,12 +1147,13 @@
 local hook_signal;
 if have_signal and signal.signalfd then
 	local function dispatch(self)
-		return self:on("signal", signal.signalfd_read(self:getfd()));
+		return self:on("signal", self.conn:read());
 	end
 
 	function hook_signal(signum, cb)
 		local watch = watchfd(signal.signalfd(signum), dispatch);
 		watch.listeners = { onsignal = cb };
+		watch.close = nil; -- revert to default
 		return watch;
 	end
 end
--- a/util-src/signal.c	Sat Feb 24 00:20:35 2024 +0100
+++ b/util-src/signal.c	Sat Feb 24 01:00:44 2024 +0100
@@ -373,29 +373,66 @@
 #endif
 
 #ifdef __linux__
+struct lsignalfd {
+	int fd;
+	sigset_t mask;
+};
+
 static int l_signalfd(lua_State *L) {
-	sigset_t mask;
+	struct lsignalfd *sfd = lua_newuserdata(L, sizeof(struct lsignalfd));
+
+	sigemptyset(&sfd->mask);
+	sigaddset(&sfd->mask, luaL_checkinteger(L, 1));
+
+	sigprocmask(SIG_BLOCK, &sfd->mask, NULL); /* TODO check err */
+
+	sfd->fd = signalfd(-1, &sfd->mask, SFD_NONBLOCK);
 
-	sigemptyset(&mask);
-	sigaddset(&mask, luaL_checkinteger(L, 1));
+	if(sfd->fd == -1) {
+		lua_pushnil(L);
+		return 1;
+	}
+
+	luaL_setmetatable(L, "signalfd");
+	return 1;
+}
 
-	sigprocmask(SIG_BLOCK, &mask, NULL); /* TODO check err */
+static int l_signalfd_getfd(lua_State *L) {
+	struct lsignalfd *sfd = luaL_checkudata(L, 1, "signalfd");
 
-	lua_pushinteger(L, signalfd(-1, &mask, SFD_NONBLOCK));
+	if (sfd->fd == -1) {
+		lua_pushnil(L);
+		return 1;
+	}
+
+	lua_pushinteger(L, sfd->fd);
 	return 1;
 }
 
 static int l_signalfd_read(lua_State *L) {
-	const int sigfd = luaL_checkinteger(L, 1);
+	struct lsignalfd *sfd = luaL_checkudata(L, 1, "signalfd");
 	struct signalfd_siginfo siginfo;
 
-	if(read(sigfd, &siginfo, sizeof(siginfo)) < 0) {
+	if(read(sfd->fd, &siginfo, sizeof(siginfo)) < 0) {
 		return 0;
 	}
 
 	lua_pushinteger(L, siginfo.ssi_signo);
 	return 1;
 }
+
+static int l_signalfd_close(lua_State *L) {
+	struct lsignalfd *sfd = luaL_checkudata(L, 1, "signalfd");
+
+	if(close(sfd->fd) != 0) {
+		lua_pushboolean(L, 0);
+		return 1;
+	}
+
+	sfd->fd = -1;
+	lua_pushboolean(L, 1);
+	return 1;
+}
 #endif
 
 static const struct luaL_Reg lsignal_lib[] = {
@@ -406,7 +443,6 @@
 #endif
 #ifdef __linux__
 	{"signalfd", l_signalfd},
-	{"signalfd_read", l_signalfd_read},
 #endif
 	{NULL, NULL}
 };
@@ -415,6 +451,23 @@
 	luaL_checkversion(L);
 	int i = 0;
 
+#ifdef __linux__
+	luaL_newmetatable(L, "signalfd");
+	lua_pushcfunction(L, l_signalfd_close);
+	lua_setfield(L, -2, "__gc");
+	lua_createtable(L, 0, 1);
+	{
+		lua_pushcfunction(L, l_signalfd_getfd);
+		lua_setfield(L, -2, "getfd");
+		lua_pushcfunction(L, l_signalfd_read);
+		lua_setfield(L, -2, "read");
+		lua_pushcfunction(L, l_signalfd_close);
+		lua_setfield(L, -2, "close");
+	}
+	lua_setfield(L, -2, "__index");
+	lua_pop(L, 1);
+#endif
+
 	/* add the library */
 	lua_newtable(L);
 	luaL_setfuncs(L, lsignal_lib, 0);