From b9f5ced260afb20f90050b44427eeff8de30e427 Mon Sep 17 00:00:00 2001 From: Richard Ipsum Date: Mon, 22 Jul 2019 03:45:27 +0100 Subject: Add signal sets and sigprocmask --- luxio.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 1 deletion(-) (limited to 'luxio.c') 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 }, -- cgit v1.2.1