moonbridge

changeset 296:ce109800ae2d

Extend moonbridge_io.poll(...) to support waiting for child process termination
author jbe
date Sat Jun 17 22:35:44 2017 +0200 (2017-06-17)
parents 1eef86d3b925
children dd0ec48592e7
files moonbridge_io.c reference.txt
line diff
     1.1 --- a/moonbridge_io.c	Sat Jun 17 20:07:03 2017 +0200
     1.2 +++ b/moonbridge_io.c	Sat Jun 17 22:35:44 2017 +0200
     1.3 @@ -1657,6 +1657,7 @@
     1.4  static int moonbr_io_poll(lua_State *L) {
     1.5    moonbr_io_handle_t *handle;
     1.6    moonbr_io_listener_t *listener;
     1.7 +  moonbr_io_child_t *child;
     1.8    int fd, isnum;
     1.9    int nfds = 0;
    1.10    fd_set readfds, writefds, exceptfds;
    1.11 @@ -1664,6 +1665,8 @@
    1.12    int force_wakeup = 0;
    1.13    int use_timeout = 0;  // negative for negative timeout
    1.14    int check_sigterm = 0;
    1.15 +  int check_child = 0;
    1.16 +  int childstatus;
    1.17    sigset_t mask, orig_mask;
    1.18    int status;
    1.19    FD_ZERO(&readfds);
    1.20 @@ -1693,8 +1696,20 @@
    1.21              fd = listener->fd;
    1.22              if (fd < 0) luaL_error(L, "Attempt to poll a closed listener");
    1.23            } else {
    1.24 -            fd = lua_tointegerx(L, -2, &isnum);
    1.25 -            if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
    1.26 +            child = luaL_testudata(L, -2, MOONBR_IO_CHILD_MT_REGKEY);
    1.27 +            if (child) {
    1.28 +              check_child = 1;
    1.29 +              if (waitpid(child->pid, &childstatus, WNOHANG|WNOWAIT) != -1) {
    1.30 +                force_wakeup = 1;
    1.31 +              } else if (errno != ECHILD && errno != EINTR) {
    1.32 +                moonbr_io_prepare_errmsg();
    1.33 +                luaL_error(L, "Error in waitpid call: %s", errmsg);
    1.34 +              }
    1.35 +              continue;
    1.36 +            } else {
    1.37 +              fd = lua_tointegerx(L, -2, &isnum);
    1.38 +              if (!isnum) luaL_error(L, "Expected integer (file descriptor), I/O handle, or listener in table key");
    1.39 +            }
    1.40            }
    1.41          }
    1.42          if (fd < 0 || fd >= FD_SETSIZE) luaL_error(L, "File descriptor out of valid range");
    1.43 @@ -1743,20 +1758,29 @@
    1.44    if (use_timeout < 0) force_wakeup = 1;
    1.45    if (!lua_isnoneornil(L, 4)) luaL_checktype(L, 4, LUA_TBOOLEAN);
    1.46    check_sigterm = lua_toboolean(L, 4);
    1.47 -  if (check_sigterm) {
    1.48 +  if ((check_sigterm || check_child) && !force_wakeup) {
    1.49 +    sigemptyset(&mask);
    1.50 +    if (check_sigterm) sigaddset(&mask, SIGTERM);
    1.51 +    if (check_child) sigaddset(&mask, SIGCHLD);
    1.52 +    if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) abort();
    1.53 +  }
    1.54 +  if (check_sigterm && moonbr_io_sigterm_flag) {
    1.55      if (!force_wakeup) {
    1.56 -      sigemptyset(&mask);
    1.57 -      sigaddset(&mask, SIGTERM);
    1.58 -      if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) abort();
    1.59 +      if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
    1.60      }
    1.61 -    if (moonbr_io_sigterm_flag) {
    1.62 -      if (!force_wakeup) {
    1.63 -        if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
    1.64 -      }
    1.65 -      lua_pushboolean(L, 0);
    1.66 -      lua_pushliteral(L, "SIGTERM received");
    1.67 -      lua_pushboolean(L, 1);
    1.68 -      return 3;
    1.69 +    lua_pushboolean(L, 0);
    1.70 +    lua_pushliteral(L, "SIGTERM received");
    1.71 +    lua_pushboolean(L, 1);
    1.72 +    return 3;
    1.73 +  }
    1.74 +  if (check_child && !force_wakeup) {
    1.75 +    if (wait3(&childstatus, WNOHANG|WNOWAIT, NULL) != -1) {
    1.76 +      if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
    1.77 +      force_wakeup = 1;
    1.78 +    } else if (errno != ECHILD && errno != EINTR) {
    1.79 +      moonbr_io_prepare_errmsg();
    1.80 +      if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
    1.81 +      luaL_error(L, "Error in waitpid call: %s", errmsg);
    1.82      }
    1.83    }
    1.84    if (use_timeout < 0) {
     2.1 --- a/reference.txt	Sat Jun 17 20:07:03 2017 +0200
     2.2 +++ b/reference.txt	Sat Jun 17 22:35:44 2017 +0200
     2.3 @@ -310,7 +310,7 @@
     2.4  
     2.5  ### moonbridge_io.exec(command, arg1, arg2, ...)
     2.6  
     2.7 -Executes the given command and returns a handle with three sockets named
     2.8 +Executes the given command and returns a child handle with three sockets named
     2.9  "stdin", "stdout", and "stderr" as well as the following methods:
    2.10  
    2.11  - :kill(signal)
    2.12 @@ -335,6 +335,9 @@
    2.13  
    2.14  The method :wait_yield() is an alias for :wait_call(coroutine.yield).
    2.15  
    2.16 +It is possible to wait for process termination by including the child handle
    2.17 +in the input_set of the moonbridge_io.poll(...) call.
    2.18 +
    2.19  moonbridge_io.exec(...) returns nil (as first return value) plus an error
    2.20  message (as second return value) in case of error.
    2.21  
    2.22 @@ -399,6 +402,9 @@
    2.23  which does evaluate to true, e.g. input_set = {[socketA] = true}. If a set is
    2.24  nil, it is treated as being empty.
    2.25  
    2.26 +The input_set may also contain listeners (to wait for incoming connections) and
    2.27 +child handles (to wait for process termination).
    2.28 +
    2.29  If the 4th parameter (wakeup_on_sigterm) is set to true, then the function
    2.30  returns immediately if the process received at least one SIGTERM signal after
    2.31  moonbridge_io.catch_sigterm() has been called for the first time. Three values

Impressum / About Us