---
luxio.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/test-sigaction.lua | 38 ++++++++++++++++++++++++++++++++++
2 files changed, 92 insertions(+)
create mode 100644 tests/test-sigaction.lua
diff --git a/luxio.c b/luxio.c
index 5013106..f339aa8 100644
--- a/luxio.c
+++ b/luxio.c
@@ -482,6 +482,58 @@ luxio_kill(lua_State *L) /* 3.3.2 */
/* TODO: Manipulate Signal Sets 3.3.3 */
/* TODO: sigaction() 3.3.4 */
+
+/* Linux defines NSIG, but it's not in POSIX, so there's no portable
+ * way to know the max number of signals, does any platform have more than 512?
+ */
+static int luxio__sigaction_handlers[512];
+
+static lua_State *luxio__sigaction_state_ref;
+
+static void luxio__sigaction_dispatch_handler(lua_State *L, int signo)
+{
+ /* push the callback onto the stack using the Lua reference we */
+ /* stored in the registry */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, luxio__sigaction_handlers[signo]);
+ lua_pushinteger(L, signo);
+
+ if (lua_pcall(L, 1, 0, 0) != 0) {
+ /* TODO: consider removing this? It's useful for debug but not in production? */
+ fprintf(stderr, "Failed to call the callback: %s\n", lua_tostring(L, -1));
+ }
+}
+
+static void luxio__sigaction_base_handler(int signo)
+{
+ luxio__sigaction_dispatch_handler(luxio__sigaction_state_ref, signo);
+}
+
+static int
+luxio_sigaction(lua_State *L)
+{
+ int signo;
+
+ struct sigaction sa = {
+ .sa_handler = luxio__sigaction_base_handler
+ };
+
+ signo = luaL_checkinteger(L, 1);
+
+ if (!lua_isfunction(L, 2)) {
+ lua_pushinteger(L, -1);
+ lua_pushinteger(L, EINVAL);
+ return 2;
+ }
+
+ luxio__sigaction_handlers[signo] = luaL_ref(L, LUA_REGISTRYINDEX);
+ luxio__sigaction_state_ref = L;
+
+ lua_pushinteger(L, sigaction(signo, &sa, NULL));
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
/* TODO: pthread_sigmask(), sigprocmask() 3.3.5 */
/* TODO: sigpending() 3.3.6 */
/* TODO: sigsuspend() 3.3.7 */
@@ -4494,6 +4546,8 @@ luxio_functions[] = {
{ "chdir", luxio_chdir },
{ "getcwd", luxio_getcwd },
+ { "sigaction", luxio_sigaction },
+
{ "alarm", luxio_alarm },
{ "pause", luxio_pause },
{ "sleep", luxio_sleep },
diff --git a/tests/test-sigaction.lua b/tests/test-sigaction.lua
new file mode 100644
index 0000000..943f81a
--- /dev/null
+++ b/tests/test-sigaction.lua
@@ -0,0 +1,38 @@
+local os = require "os"
+local l = require "luxio"
+local io = require "io"
+
+function MyCallback(signo)
+ print("Hello World!", signo)
+end
+
+function MyGoodbyeCallback(signo)
+ print("Goodbye cruel world!", signo)
+end
+
+function MySIGTERMCallback(signo)
+ print("SIGTERM !!!!", signo)
+ os.exit(os.EXIT_SUCCESS)
+end
+
+r, errno = l.sigaction(l.SIGINT, MyCallback)
+if r == -1 then
+ io.stderr:write(("sigaction: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+r, errno = l.sigaction(l.SIGINT, MyGoodbyeCallback)
+if r == -1 then
+ io.stderr:write(("sigaction: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+r, errno = l.sigaction(l.SIGTERM, MySIGTERMCallback)
+if r == -1 then
+ io.stderr:write(("sigaction: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+while (true) do
+ l.sleep(0.5)
+end
--
2.11.0