summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Ipsum <richardipsum@fastmail.co.uk>2019-07-22 03:45:27 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2019-07-28 09:58:30 +0100
commitb9f5ced260afb20f90050b44427eeff8de30e427 (patch)
tree6e89c6c156fb0d4b47be8422ad4289365d108916
parentad5af52f76de82e6fa4607cc339ef4eb8e6370d6 (diff)
downloadluxio-b9f5ced260afb20f90050b44427eeff8de30e427.tar.gz
Add signal sets and sigprocmask
-rw-r--r--luxio.c206
-rw-r--r--luxio_constants.inc.in3
-rw-r--r--tests/test-sigprocmask.lua109
3 files changed, 317 insertions, 1 deletions
diff --git a/luxio.c b/luxio.c
index f3e298d..0db4979 100644
--- a/luxio.c
+++ b/luxio.c
@@ -480,7 +480,144 @@ luxio_kill(lua_State *L) /* 3.3.2 */
/* Signals are going to be almost impossible to do nicely and safely. */
-/* TODO: Manipulate Signal Sets 3.3.3 */
+#define LUXIO_SIGNALSET_METATABLE "luxio.signalset"
+
+typedef struct {
+ sigset_t set;
+} luxio_signalset;
+
+static int
+luxio_signalset_tostring(lua_State *L)
+{
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE);
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), "sigset: %p", &s->set);
+ lua_pushstring(L, buf);
+
+ return 1;
+}
+
+static void
+luxio__bless_signalset(lua_State *L)
+{
+ int create = luaL_newmetatable(L, LUXIO_SIGNALSET_METATABLE);
+
+ if (create != 0) {
+ lua_pushcfunction(L, luxio_signalset_tostring);
+ lua_setfield(L, -2, "__tostring");
+ }
+
+ lua_setmetatable(L, -2);
+}
+
+/*** Create a new signal set
+@treturn A new signal set
+*/
+static int
+luxio_newsigset(lua_State *L)
+{
+ luxio_signalset *s = lua_newuserdata(L, sizeof(*s));
+
+ luxio__bless_signalset(L);
+
+ return 1;
+}
+
+/*** Initialise a signal set to be empty.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigemptyset
+*/
+static int
+luxio_sigemptyset(lua_State *L)
+{
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE);
+ lua_pushinteger(L, sigemptyset(&s->set));
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
+/*** Initialise a signal set to contain all signals.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigfillset
+*/
+static int
+luxio_sigfillset(lua_State *L)
+{
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE);
+ lua_pushinteger(L, sigfillset(&s->set));
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
+#define LUXIO__SIGSET_OPERATION(L, op) do { \
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE); \
+ int signo = luaL_checkinteger(L, 2); \
+ lua_pushinteger(L, op(&s->set, signo)); \
+ lua_pushinteger(L, errno); \
+ return 2; \
+} while (0)
+
+/*** Add a signal to a signal set.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigaddset
+*/
+static int
+luxio_sigaddset(lua_State *L)
+{
+ LUXIO__SIGSET_OPERATION(L, sigaddset);
+}
+
+/*** Remove a signal from a signal set.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigdelset
+*/
+static int
+luxio_sigdelset(lua_State *L)
+{
+ LUXIO__SIGSET_OPERATION(L, sigdelset);
+}
+
+/*** Check whether a signal set contains a given signal.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigismember
+*/
+static int luxio_sigismember(lua_State *L)
+{
+ LUXIO__SIGSET_OPERATION(L, sigismember);
+}
/* NSIG is not in POSIX, it's 64 on Linux and 33 on OpenBSD
* we define a value much larger than either to be on the safe side */
@@ -703,6 +840,10 @@ luxio_sigaction(lua_State *L)
} else {
goto einval;
}
+ } else if (strcmp(key, "sa_mask") == 0) {
+ luxio_signalset *s = luaL_checkudata(L, -1, LUXIO_SIGNALSET_METATABLE);
+ sa.sa_mask = s->set;
+ lua_pop(L, 1);
} else if (strcmp(key, "sa_flags") == 0) {
sa.sa_flags = luaL_checkint(L, -1);
lua_pop(L, 1);
@@ -738,6 +879,61 @@ enospc:
}
/* TODO: pthread_sigmask(), sigprocmask() 3.3.5 */
+
+/*** Manipulate the current signal mask.
+
+sigprocmask examines and/or changes the current process signal mask.
+Signals are blocked if they are members of the current signal mask set.
+
+The action performed by sigprocmask depends on the value of `how`,
+which can be one of:
+
+- `luxio.SIG_BLOCK` - The new mask is the existing mask plus all of the
+signals in the specified set.
+
+- `luxio.SIG_UNBLOCK` - The new mask is the existing mask minus the signals
+contained within the specified set.
+
+- `luxio.SIG_SETMASK` - The current mask is replaced with the specified set.
+
+On success the previous signal mask will be returned, otherwise on error
+nil will be returned and errno will be set appropriately.
+
+If the `set` parameter is set to nil then the current signal mask will
+be returned without performing any modification to the current signal mask,
+and the `how` parameter will be ignored.
+
+@tparam number how Action to perform on signal mask
+@tparam sigset set signal set
+@treturn return number return value
+@treturn errno
+@function sigprocmask
+*/
+static int
+luxio_sigprocmask(lua_State *L)
+{
+ int how = luaL_checkinteger(L, 1);
+ void *p = lua_touserdata(L, 2);
+ sigset_t orig, *set = NULL;
+
+ if (p != NULL) {
+ luxio_signalset *s = luaL_checkudata(L, 2, LUXIO_SIGNALSET_METATABLE);
+ set = &s->set;
+ }
+
+ if (sigprocmask(how, set, &orig) == -1) {
+ lua_pushnil(L);
+ } else {
+ luxio_signalset *o = lua_newuserdata(L, sizeof(*o));
+ o->set = orig;
+ luxio__bless_signalset(L);
+ }
+
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
/* TODO: sigpending() 3.3.6 */
/* TODO: sigsuspend() 3.3.7 */
/* TODO: sigwait(), sigwaitinfo(), sigtimedwait() 3.3.8 */
@@ -4818,7 +5014,15 @@ luxio_functions[] = {
{ "chdir", luxio_chdir },
{ "getcwd", luxio_getcwd },
+ { "newsigset", luxio_newsigset },
+ { "sigemptyset", luxio_sigemptyset },
+ { "sigfillset", luxio_sigfillset },
+ { "sigaddset", luxio_sigaddset },
+ { "sigdelset", luxio_sigdelset },
+ { "sigismember", luxio_sigismember },
+
{ "sigaction", luxio_sigaction },
+ { "sigprocmask", luxio_sigprocmask },
{ "alarm", luxio_alarm },
{ "pause", luxio_pause },
diff --git a/luxio_constants.inc.in b/luxio_constants.inc.in
index ef3cadb..22a1f13 100644
--- a/luxio_constants.inc.in
+++ b/luxio_constants.inc.in
@@ -216,6 +216,9 @@ static const struct {
/* signals */
{"SIG_DFL", (int) SIG_DFL},
{"SIG_IGN", (int) SIG_IGN},
+ E(SIG_BLOCK),
+ E(SIG_UNBLOCK),
+ E(SIG_SETMASK),
E(SIGHUP),
E(SIGINT),
E(SIGQUIT),
diff --git a/tests/test-sigprocmask.lua b/tests/test-sigprocmask.lua
new file mode 100644
index 0000000..490672b
--- /dev/null
+++ b/tests/test-sigprocmask.lua
@@ -0,0 +1,109 @@
+local l = require "luxio"
+
+set = l.newsigset()
+
+r, errno = l.sigemptyset(set)
+if r == -1 then
+ io.stderr:write(("sigemptyset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("Empty set", set)
+
+r, errno = l.sigfillset(set)
+if r == -1 then
+ io.stderr:write(("sigfillset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("Full set", set)
+
+r, errno = l.sigismember(set, l.SIGINT)
+if r == -1 then
+ io.stderr:write(("sigismember: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("SIGINT is member of set?", r == 1 and "yes" or "no")
+
+print("sigdelset(set, SIGINT)...")
+r, errno = l.sigdelset(set, l.SIGINT)
+if r == -1 then
+ io.stderr:write(("sigdelset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+r, errno = l.sigismember(set, l.SIGINT)
+if r == -1 then
+ io.stderr:write(("sigismember: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("SIGINT is member of set?", r == 1 and "yes" or "no")
+
+print("l.sigemptyset(set)...")
+r, errno = l.sigemptyset(set)
+if r == -1 then
+ io.stderr:write(("sigemptyset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("Empty set", set)
+
+
+to_block = {["SIGINT"] = l.SIGINT, ["SIGUSR1"] = l.SIGUSR1}
+
+for signame, signo in pairs(to_block) do
+ print(("sigaddset(set, %s)..."):format(signame))
+ r, errno = l.sigaddset(set, signo)
+ if r == -1 then
+ io.stderr:write(("sigaddset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+ end
+
+ r, errno = l.sigismember(set, signo)
+ if r == -1 then
+ io.stderr:write(("sigismember: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+ end
+
+ print(("%s is member of set?"):format(signame), r == 1 and "yes" or "no")
+end
+
+origset, errno = l.sigprocmask(0, nil)
+if origset == nil then
+ io.stderr:write(("sigprocmask: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+print("Got the current signal set", origset)
+
+print("set", set)
+origset, errno = l.sigprocmask(l.SIG_BLOCK, set)
+if origset == nil then
+ io.stderr:write(("sigprocmask: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+print("origset", origset)
+
+i = 1
+while (i <= 5) do
+ print(i)
+ l.sleep(2)
+ i = i + 1
+end
+
+print("restoring original signal mask...")
+
+origset, errno = l.sigprocmask(l.SIG_SETMASK, origset)
+if origset == nil then
+ io.stderr:write(("sigprocmask: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("done")
+print("origset", origset)
+
+while (true) do
+ l.sleep(2)
+ print("sleep")
+end