diff options
author | Richard Ipsum <richardipsum@vx21.xyz> | 2019-10-04 23:28:49 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2019-10-06 09:22:07 +0100 |
commit | 4c42af5fd9b2bb8cc2c37c71314b8c443cf80392 (patch) | |
tree | c3993b270ccdfa757ba310c42da0ae7c5b9d9351 | |
parent | edeef019e8ad8b60f0547a854dc7763f98ff4c40 (diff) | |
download | luxio-4c42af5fd9b2bb8cc2c37c71314b8c443cf80392.tar.gz |
Add sigpending, sigsuspend, sigwait, sigwaitinfo, sigtimedwait and raise
-rw-r--r-- | luxio.c | 282 | ||||
-rw-r--r-- | tests/test-sigpending.lua | 17 | ||||
-rw-r--r-- | tests/test-sigsuspend.lua | 15 | ||||
-rw-r--r-- | tests/test-sigtimedwait.lua | 37 | ||||
-rw-r--r-- | tests/test-sigwait.lua | 21 | ||||
-rw-r--r-- | tests/test-sigwaitinfo.lua | 21 |
6 files changed, 353 insertions, 40 deletions
@@ -606,10 +606,12 @@ luxio_sigdelset(lua_State *L) /*** Check whether a signal set contains a given signal. -Return 0 on success, or -1 on error with errno set appropriately. +Return 1 if signal is a member of the set, or 0 if the signal is +not a member of the set. A return value of -1 indicates that an error +occurred and errno will be set accordingly. -@tparam sigset signal set -@tparam number signo signal +@tparam sigset set +@tparam number signal @treturn number return value @treturn errno errno @function sigismember @@ -640,56 +642,66 @@ static struct { bool sigaction; } luxio__signal_ctx; -static void luxio__sigaction_hook(lua_State *L, lua_Debug *ar) +static void luxio__push_siginfo_table(lua_State *L, const siginfo_t *info) { - int nargs = 1; + lua_newtable(L); - /* Push the callback onto the stack using the Lua reference we */ - /* stored in the registry */ - lua_rawgeti(L, LUA_REGISTRYINDEX, - luxio__signal_ctx.handlers[luxio__signal_ctx.signo].handler_fn); - lua_pushinteger(L, luxio__signal_ctx.signo); + lua_pushinteger(L, info->si_signo); + lua_setfield(L, -2, "si_signo"); - if (luxio__signal_ctx.sigaction) { - nargs++; + lua_pushinteger(L, info->si_code); + lua_setfield(L, -2, "si_code"); - if (luxio__signal_ctx.isinfo) { - siginfo_t *info = &luxio__signal_ctx.info; - lua_newtable(L); + lua_pushinteger(L, info->si_errno); + lua_setfield(L, -2, "si_errno"); - lua_pushinteger(L, info->si_signo); - lua_setfield(L, -2, "si_signo"); + lua_pushinteger(L, info->si_pid); + lua_setfield(L, -2, "si_pid"); - lua_pushinteger(L, info->si_code); - lua_setfield(L, -2, "si_code"); + lua_pushinteger(L, info->si_uid); + lua_setfield(L, -2, "si_uid"); - lua_pushinteger(L, info->si_errno); - lua_setfield(L, -2, "si_errno"); + lua_pushinteger(L, info->si_utime); + lua_setfield(L, -2, "si_utime"); - lua_pushinteger(L, info->si_pid); - lua_setfield(L, -2, "si_pid"); + lua_pushinteger(L, info->si_stime); + lua_setfield(L, -2, "si_stime"); - lua_pushinteger(L, info->si_uid); - lua_setfield(L, -2, "si_uid"); + lua_pushinteger(L, (lua_Integer) info->si_addr); + lua_setfield(L, -2, "si_addr"); + + lua_pushinteger(L, info->si_status); + lua_setfield(L, -2, "si_status"); #ifndef __FreeBSD__ - lua_pushinteger(L, info->si_utime); - lua_setfield(L, -2, "si_utime"); + lua_pushinteger(L, info->si_utime); + lua_setfield(L, -2, "si_utime"); - lua_pushinteger(L, info->si_stime); - lua_setfield(L, -2, "si_stime"); + lua_pushinteger(L, info->si_stime); + lua_setfield(L, -2, "si_stime"); #endif - lua_pushinteger(L, (lua_Integer) info->si_addr); - lua_setfield(L, -2, "si_addr"); - - lua_pushinteger(L, info->si_status); - lua_setfield(L, -2, "si_status"); - #ifdef __linux__ - lua_pushinteger(L, info->si_band); - lua_setfield(L, -2, "si_band"); + lua_pushinteger(L, info->si_band); + lua_setfield(L, -2, "si_band"); #endif +} + +static void luxio__sigaction_hook(lua_State *L, lua_Debug *ar) +{ + int nargs = 1; + + /* Push the callback onto the stack using the Lua reference we */ + /* stored in the registry */ + lua_rawgeti(L, LUA_REGISTRYINDEX, + luxio__signal_ctx.handlers[luxio__signal_ctx.signo].handler_fn); + lua_pushinteger(L, luxio__signal_ctx.signo); + + if (luxio__signal_ctx.sigaction) { + nargs++; + + if (luxio__signal_ctx.isinfo) { + luxio__push_siginfo_table(L, &luxio__signal_ctx.info); } else { lua_pushnil(L); } @@ -936,9 +948,190 @@ luxio_sigprocmask(lua_State *L) return 2; } -/* TODO: sigpending() 3.3.6 */ -/* TODO: sigsuspend() 3.3.7 */ -/* TODO: sigwait(), sigwaitinfo(), sigtimedwait() 3.3.8 */ +/*** Send a signal to the calling process. + +@tparam sig signal The signal to send +@treturn number return value +@treturn errno +@function raise +*/ +static int +luxio_raise(lua_State *L) +{ + int sig = luaL_checkinteger(L, 1); + + lua_pushinteger(L, raise(sig)); + lua_pushinteger(L, errno); + return 2; +} + +/*** Return set of signals pending for the calling process. + +@treturn sigset|nil set of pending signals, or nil on error +@treturn errno +@function sigpending +*/ +static int +luxio_sigpending(lua_State *L) +{ + sigset_t s; + luxio_signalset *pending; + + if (sigpending(&s) == -1) { + lua_pushinteger(L, -1); + } else { + pending = lua_newuserdata(L, sizeof(*pending)); + pending->set = s; + luxio__bless_signalset(L); + } + + lua_pushinteger(L, errno); + return 2; +} + +/*** Suspend execution of calling process until signal is delivered. + +sigsuspend temporarily replaces the signal mask of the calling +process with another mask until delivery of a signal that is not +masked occurs. sigsuspend always returns -1, with errno set to +indicate the error (which is generally EINTR). Upon returning +sigsuspend will restore the original signal mask that was replaced. + +@tparam set mask +@treturn number return value +@treturn errno +@function sigsuspend +*/ +static int +luxio_sigsuspend(lua_State *L) +{ + luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE); + + lua_pushinteger(L, sigsuspend(&s->set)); + lua_pushinteger(L, errno); + return 2; +} + +/*** Suspend execution of calling process until signal becomes pending. + +sigwait temporarily waits for any one of the signals provided in +the set parameter to become pending. The signal that becomes +pending will be removed from the set. On success the pending signal +will be returned, otherwise nil is returned and errno is set accordingly. + +@tparam set set of signals to wait on +@treturn number|nil signal, or nil on error +@treturn errno +@function sigwait +*/ +static int +luxio_sigwait(lua_State *L) +{ + luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE); + int sig; + + if (sigwait(&s->set, &sig) == -1) { + lua_pushnil(L); + } else { + lua_pushinteger(L, sig); + } + + lua_pushinteger(L, errno); + return 2; +} + +#ifdef __linux__ +/*** Suspend execution of calling process until signal becomes pending. + +Linux only. + +sigwaitinfo suspends execution of the calling process until one of +the signals provided in the set parameter is pending. If one of +the signals is already pending then sigwaitinfo will return without +suspending execution. + +sigwaitinfo returns the info table for the signal that was received +and removes that signal from the set argument. + +If multiple signals are pending then the signal returned by sigwaitinfo is +determined using the usual rules detailed in signal(7). + +@tparam set set of signals to wait on +@treturn sigwaitinfo-table|nil signal info table, or nil on error +@treturn errno +@function sigwaitinfo +*/ + +/*** sigwaitinfo() table +@table sigwaitinfo-table +@field si_signo Signal number +@field si_code Signal code +@field si_errno An errno value +@field si_pid Sending process ID +@field si_uid Real user ID of sending process +@field si_utime User time consumed +@field si_stime System time consumed +@field si_addr Memory location which caused fault +@field si_status Exit value or signal +@field si_band Band event (Linux only) +*/ + +static int +luxio_sigwaitinfo(lua_State *L) +{ + luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE); + siginfo_t info; + + if (sigwaitinfo(&s->set, &info) == -1) { + lua_pushnil(L); + } else { + luxio__push_siginfo_table(L, &info); + } + + lua_pushinteger(L, errno); + return 2; +} + +/*** Suspend execution of process for a given time period +or until signal is delivered. + +Linux only. + +sigtimedwait behaves exactly as sigwaitinfo but will suspend execution +for a given time period specified by the (seconds, nanoseconds) arguments. +If both of the (seconds, nanoseconds) arguments are 0 then the function +polls for pending signals rather than suspending execution until a signal +becomes pending. On success a signal info table for the pending signal +is returned, otherwise nil is returned and errno is set accordingly. + +@tparam set set of signals to wait on +@tparam number seconds +@tparam number nanoseconds +@treturn sigwaitinfo-table|nil signal info table, or nil on error +@treturn errno +@function sigtimedwait +*/ + +static int +luxio_sigtimedwait(lua_State *L) +{ + luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE); + siginfo_t info; + time_t tv_secs = luaL_checkinteger(L, 2); + long tv_nsec = luaL_checkinteger(L, 3); + struct timespec timeout = { tv_secs, tv_nsec }; + + if (sigtimedwait(&s->set, &info, &timeout) == -1) { + lua_pushnil(L); + } else { + luxio__push_siginfo_table(L, &info); + } + + lua_pushinteger(L, errno); + return 2; +} +#endif + /* TODO: sigqueue() 3.3.9 */ /* TODO: pthread_kill() 3.3.10 */ @@ -3829,6 +4022,7 @@ luxio_gai_strerror(lua_State *L) @tparam[opt=AF_UNSPEC] number ai_family @tparam[opt=0] number ai_socktype @tparam[opt=0] number ai_protocol +@treturn number return value @treturn errno|table table of result `addrinfo` entries @function getaddrinfo */ @@ -5025,7 +5219,15 @@ luxio_functions[] = { { "sigaction", luxio_sigaction }, { "sigprocmask", luxio_sigprocmask }, + { "sigpending", luxio_sigpending }, + { "sigsuspend", luxio_sigsuspend }, + { "sigwait", luxio_sigwait }, +#ifdef __linux__ + { "sigwaitinfo", luxio_sigwaitinfo }, + { "sigtimedwait", luxio_sigtimedwait }, +#endif + { "raise", luxio_raise }, { "alarm", luxio_alarm }, { "pause", luxio_pause }, { "sleep", luxio_sleep }, diff --git a/tests/test-sigpending.lua b/tests/test-sigpending.lua new file mode 100644 index 0000000..43136b1 --- /dev/null +++ b/tests/test-sigpending.lua @@ -0,0 +1,17 @@ +local l = require "luxio" + +s = l.newsigset() +l.sigemptyset(s) +l.sigaddset(s, l.SIGUSR1) +l.sigprocmask(l.SIG_BLOCK, s) +l.raise(l.SIGUSR1) + +pending = l.sigpending() + +present, errno = l.sigismember(pending, l.SIGUSR1) + +if present == 1 then + print("PASS") +else + print("FAIL") +end diff --git a/tests/test-sigsuspend.lua b/tests/test-sigsuspend.lua new file mode 100644 index 0000000..5c85e77 --- /dev/null +++ b/tests/test-sigsuspend.lua @@ -0,0 +1,15 @@ +local l = require "luxio" + +function handler() + return +end + +l.sigaction(l.SIGINT, {["sa_handler"] = handler}) + +s = l.newsigset() +l.sigfillset(s) +l.sigdelset(s, l.SIGINT) +print("Press CTRL-C...") +l.sigsuspend(s) + +print("PASS") diff --git a/tests/test-sigtimedwait.lua b/tests/test-sigtimedwait.lua new file mode 100644 index 0000000..0311a50 --- /dev/null +++ b/tests/test-sigtimedwait.lua @@ -0,0 +1,37 @@ +local l = require "luxio" + +function handler() + return +end + +l.sigaction(l.SIGINT, {["sa_handler"] = handler}) + +s = l.newsigset() +l.sigemptyset(s) +l.sigaddset(s, l.SIGINT) + +info, errno = l.sigtimedwait(s, 0, 0) + +if not (info == nil and errno == l.EAGAIN) then + print("FAIL") +end + +print("Wait...") +pid, errno = l.fork() +if pid == 0 then + l.sleep(5) + print("Press CTRL-C...") + os.exit(0) +elseif pid == -1 then + io.stderr:write(("fork: %s\n"):format(l.strerror(errno))) + os.exit(2) +end + +seconds = 3600 +info, errno = l.sigtimedwait(s, seconds, 0) + +if info ~= nil and info["si_signo"] == l.SIGINT then + print("PASS") +else + print(("FAIL (expected sig to be %d but it is %d)"):format(l.SIGINT, info["si_signo"])) +end diff --git a/tests/test-sigwait.lua b/tests/test-sigwait.lua new file mode 100644 index 0000000..bbd2378 --- /dev/null +++ b/tests/test-sigwait.lua @@ -0,0 +1,21 @@ +local l = require "luxio" + +function handler() + return +end + +l.sigaction(l.SIGINT, {["sa_handler"] = handler}) + +s = l.newsigset() +l.sigemptyset(s) +l.sigaddset(s, l.SIGINT) +print("Press CTRL-C...") + + +sig, errno = l.sigwait(s, l.SIGINT) + +if sig == l.SIGINT then + print("PASS") +else + print(("FAIL (expected sig to be %d but it is %d)"):format(l.SIGINT, sig)) +end diff --git a/tests/test-sigwaitinfo.lua b/tests/test-sigwaitinfo.lua new file mode 100644 index 0000000..242b444 --- /dev/null +++ b/tests/test-sigwaitinfo.lua @@ -0,0 +1,21 @@ +local l = require "luxio" + +function handler() + return +end + +l.sigaction(l.SIGINT, {["sa_handler"] = handler}) + +s = l.newsigset() +l.sigemptyset(s) +l.sigaddset(s, l.SIGINT) +print("Press CTRL-C...") + + +info, errno = l.sigwaitinfo(s) + +if info ~= nil and info["si_signo"] == l.SIGINT then + print("PASS") +else + print(("FAIL (expected sig to be %d but it is %d)"):format(l.SIGINT, info["si_signo"])) +end |