summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Ipsum <richardipsum@vx21.xyz>2019-10-04 23:28:49 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2019-10-06 09:22:07 +0100
commit4c42af5fd9b2bb8cc2c37c71314b8c443cf80392 (patch)
treec3993b270ccdfa757ba310c42da0ae7c5b9d9351
parentedeef019e8ad8b60f0547a854dc7763f98ff4c40 (diff)
downloadluxio-4c42af5fd9b2bb8cc2c37c71314b8c443cf80392.tar.bz2
Add sigpending, sigsuspend, sigwait, sigwaitinfo, sigtimedwait and raise
-rw-r--r--luxio.c282
-rw-r--r--tests/test-sigpending.lua17
-rw-r--r--tests/test-sigsuspend.lua15
-rw-r--r--tests/test-sigtimedwait.lua37
-rw-r--r--tests/test-sigwait.lua21
-rw-r--r--tests/test-sigwaitinfo.lua21
6 files changed, 353 insertions, 40 deletions
diff --git a/luxio.c b/luxio.c
index e31fd8d..e5b370c 100644
--- a/luxio.c
+++ b/luxio.c
@@ -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