# HG changeset patch # User jbe # Date 1497731744 -7200 # Node ID ce109800ae2dd5ae7ff32ae0f32dd083e7d0246b # Parent 1eef86d3b9255ee107045832692d813739d2f7ca Extend moonbridge_io.poll(...) to support waiting for child process termination diff -r 1eef86d3b925 -r ce109800ae2d moonbridge_io.c --- a/moonbridge_io.c Sat Jun 17 20:07:03 2017 +0200 +++ b/moonbridge_io.c Sat Jun 17 22:35:44 2017 +0200 @@ -1657,6 +1657,7 @@ static int moonbr_io_poll(lua_State *L) { moonbr_io_handle_t *handle; moonbr_io_listener_t *listener; + moonbr_io_child_t *child; int fd, isnum; int nfds = 0; fd_set readfds, writefds, exceptfds; @@ -1664,6 +1665,8 @@ int force_wakeup = 0; int use_timeout = 0; // negative for negative timeout int check_sigterm = 0; + int check_child = 0; + int childstatus; sigset_t mask, orig_mask; int status; FD_ZERO(&readfds); @@ -1693,8 +1696,20 @@ fd = listener->fd; if (fd < 0) luaL_error(L, "Attempt to poll a closed listener"); } else { - fd = lua_tointegerx(L, -2, &isnum); - if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key"); + child = luaL_testudata(L, -2, MOONBR_IO_CHILD_MT_REGKEY); + if (child) { + check_child = 1; + if (waitpid(child->pid, &childstatus, WNOHANG|WNOWAIT) != -1) { + force_wakeup = 1; + } else if (errno != ECHILD && errno != EINTR) { + moonbr_io_prepare_errmsg(); + luaL_error(L, "Error in waitpid call: %s", errmsg); + } + continue; + } else { + fd = lua_tointegerx(L, -2, &isnum); + if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key"); + } } } if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range"); @@ -1743,20 +1758,29 @@ if (use_timeout < 0) force_wakeup = 1; if (!lua_isnoneornil(L, 4)) luaL_checktype(L, 4, LUA_TBOOLEAN); check_sigterm = lua_toboolean(L, 4); - if (check_sigterm) { + if ((check_sigterm || check_child) && !force_wakeup) { + sigemptyset(&mask); + if (check_sigterm) sigaddset(&mask, SIGTERM); + if (check_child) sigaddset(&mask, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) abort(); + } + if (check_sigterm && moonbr_io_sigterm_flag) { if (!force_wakeup) { - sigemptyset(&mask); - sigaddset(&mask, SIGTERM); - if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) abort(); + if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort(); } - if (moonbr_io_sigterm_flag) { - if (!force_wakeup) { - if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort(); - } - lua_pushboolean(L, 0); - lua_pushliteral(L, "SIGTERM received"); - lua_pushboolean(L, 1); - return 3; + lua_pushboolean(L, 0); + lua_pushliteral(L, "SIGTERM received"); + lua_pushboolean(L, 1); + return 3; + } + if (check_child && !force_wakeup) { + if (wait3(&childstatus, WNOHANG|WNOWAIT, NULL) != -1) { + if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort(); + force_wakeup = 1; + } else if (errno != ECHILD && errno != EINTR) { + moonbr_io_prepare_errmsg(); + if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort(); + luaL_error(L, "Error in waitpid call: %s", errmsg); } } if (use_timeout < 0) { diff -r 1eef86d3b925 -r ce109800ae2d reference.txt --- a/reference.txt Sat Jun 17 20:07:03 2017 +0200 +++ b/reference.txt Sat Jun 17 22:35:44 2017 +0200 @@ -310,7 +310,7 @@ ### moonbridge_io.exec(command, arg1, arg2, ...) -Executes the given command and returns a handle with three sockets named +Executes the given command and returns a child handle with three sockets named "stdin", "stdout", and "stderr" as well as the following methods: - :kill(signal) @@ -335,6 +335,9 @@ The method :wait_yield() is an alias for :wait_call(coroutine.yield). +It is possible to wait for process termination by including the child handle +in the input_set of the moonbridge_io.poll(...) call. + moonbridge_io.exec(...) returns nil (as first return value) plus an error message (as second return value) in case of error. @@ -399,6 +402,9 @@ which does evaluate to true, e.g. input_set = {[socketA] = true}. If a set is nil, it is treated as being empty. +The input_set may also contain listeners (to wait for incoming connections) and +child handles (to wait for process termination). + If the 4th parameter (wakeup_on_sigterm) is set to true, then the function returns immediately if the process received at least one SIGTERM signal after moonbridge_io.catch_sigterm() has been called for the first time. Three values