diff options
author | Richard Ipsum <richardipsum@fastmail.co.uk> | 2019-07-22 03:45:27 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2019-07-28 09:58:30 +0100 |
commit | b9f5ced260afb20f90050b44427eeff8de30e427 (patch) | |
tree | 6e89c6c156fb0d4b47be8422ad4289365d108916 | |
parent | ad5af52f76de82e6fa4607cc339ef4eb8e6370d6 (diff) | |
download | luxio-b9f5ced260afb20f90050b44427eeff8de30e427.tar.gz |
Add signal sets and sigprocmask
-rw-r--r-- | luxio.c | 206 | ||||
-rw-r--r-- | luxio_constants.inc.in | 3 | ||||
-rw-r--r-- | tests/test-sigprocmask.lua | 109 |
3 files changed, 317 insertions, 1 deletions
@@ -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 |