summaryrefslogtreecommitdiff
path: root/luxio.c
diff options
context:
space:
mode:
Diffstat (limited to 'luxio.c')
-rw-r--r--luxio.c282
1 files changed, 242 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 },