moonbridge

changeset 284:28aab22e68b6

New implementation of SIGTERM handling
author jbe
date Sun Jun 11 00:02:43 2017 +0200 (2017-06-11)
parents 245406b9e43c
children a7395fb91ec3
files moonbridge.c moonbridge_io.c moonbridge_io.h reference.txt
line diff
     1.1 --- a/moonbridge.c	Fri Jun 09 18:33:57 2017 +0200
     1.2 +++ b/moonbridge.c	Sun Jun 11 00:02:43 2017 +0200
     1.3 @@ -755,6 +755,7 @@
     1.4    char controlmsg;
     1.5    int fd;
     1.6    struct itimerval notimer = { { 0, }, { 0, } };
     1.7 +  moonbr_io_sigterm_setup(L);  // NOTE: should not fail
     1.8    lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
     1.9    if (lua_isnil(L, -1)) lua_pop(L, 1);
    1.10    else if (lua_pcall(L, 0, 0, 1)) {
     2.1 --- a/moonbridge_io.c	Fri Jun 09 18:33:57 2017 +0200
     2.2 +++ b/moonbridge_io.c	Sun Jun 11 00:02:43 2017 +0200
     2.3 @@ -55,18 +55,12 @@
     2.4      moonbr_io_return_prepared_errmsg(); \
     2.5    } while (0)
     2.6  
     2.7 -#define MOONBR_IO_MAXSIGNUM 127
     2.8 -static int moonbr_io_signalfds[2*(MOONBR_IO_MAXSIGNUM+1)];
     2.9 -#define moonbr_io_signalfd_read(x) moonbr_io_signalfds[2*(x)+0]
    2.10 -#define moonbr_io_signalfd_write(x) moonbr_io_signalfds[2*(x)+1]
    2.11 -
    2.12  #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
    2.13  #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
    2.14  #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
    2.15  #define MOONBR_IO_CHILD_MT_REGKEY "moonbridge_io_child"
    2.16  #define MOONBR_IO_CHILD_PT_REGKEY "moonbridge_io_child_pt"
    2.17  #define MOONBR_IO_SIGNALS_REGKEY "moonbridge_io_signals"
    2.18 -#define MOONBR_IO_SIGNALSOCKETS_REGKEY "moonbridge_io_signalsockets"
    2.19  
    2.20  #ifdef MOONBR_IO_USE_TLS
    2.21  
    2.22 @@ -123,6 +117,8 @@
    2.23    pid_t pid;
    2.24  } moonbr_io_child_t;
    2.25  
    2.26 +static volatile sig_atomic_t moonbr_io_sigterm_flag = 0;
    2.27 +
    2.28  static int moonbr_io_yield(lua_State *L) {
    2.29    return lua_yield(L, lua_gettop(L));
    2.30  }
    2.31 @@ -1627,48 +1623,17 @@
    2.32  
    2.33  moonbr_io_yield_wrapper(moonbr_io_wait_yield, moonbr_io_wait_call);
    2.34  
    2.35 -static void moonbr_io_signalhandler(int sig) {
    2.36 -  int errno2 = errno;
    2.37 -  char buf[1] = {'.'};
    2.38 -  write(moonbr_io_signalfd_write(sig), buf, 1);
    2.39 -  errno = errno2;
    2.40 +static void moonbr_io_sigterm_handler(int sig) {
    2.41 +  moonbr_io_sigterm_flag = 1;
    2.42  }
    2.43  
    2.44 -static int moonbr_io_signalsocket(lua_State *L) {
    2.45 -  int sig, fd;
    2.46 -  if (lua_type(L, 1) == LUA_TSTRING) {
    2.47 -    lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALS_REGKEY);
    2.48 -    lua_pushvalue(L, 1);
    2.49 -    lua_gettable(L, -2);
    2.50 -    sig = lua_tointeger(L, -1);
    2.51 -    if (!sig) {
    2.52 -      lua_pushvalue(L, 1);
    2.53 -      luaL_error(L, "Unknown signal \"%s\"", lua_tostring(L, 1));
    2.54 -    }
    2.55 -  } else {
    2.56 -    sig = luaL_checkinteger(L, 1);
    2.57 -  }
    2.58 -  if (sig < 1 || sig > MOONBR_IO_MAXSIGNUM) {
    2.59 -    luaL_error(L, "Signal number %i out of range", sig);
    2.60 -  }
    2.61 -  if (moonbr_io_signalfd_read(sig) < 0) {
    2.62 -    if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, moonbr_io_signalfds+2*sig)) {
    2.63 -      luaL_error(L, "Could not create socket pair for signal queueing");
    2.64 -    }
    2.65 -  }
    2.66 -  errno = 0;
    2.67 -  signal(sig, moonbr_io_signalhandler);
    2.68 -  if (errno) luaL_error(L, "Could not install signal handler (invalid signal number %i?)", sig);
    2.69 -  lua_getfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALSOCKETS_REGKEY);
    2.70 -  lua_pushinteger(L, sig);
    2.71 -  lua_gettable(L, -2);
    2.72 -  if (!lua_isnil(L, -1)) return 1;
    2.73 -  fd = dup(moonbr_io_signalfd_read(sig));  /* avoid close on Lua error */
    2.74 -  if (fd < 0) luaL_error(L, "Could not create duplicated file descriptor for signal socket");
    2.75 -  moonbr_io_pushhandle(L, fd);
    2.76 -  lua_pushinteger(L, sig);
    2.77 -  lua_pushvalue(L, -2);
    2.78 -  lua_settable(L, -5);  /* store reference to signal socket in cache table */
    2.79 +int moonbr_io_sigterm_setup(lua_State *L) {
    2.80 +  signal(SIGTERM, moonbr_io_sigterm_handler);
    2.81 +  return 0;
    2.82 +}
    2.83 +
    2.84 +static int moonbr_io_sigterm_received(lua_State *L) {
    2.85 +  lua_pushboolean(L, moonbr_io_sigterm_flag);
    2.86    return 1;
    2.87  }
    2.88  
    2.89 @@ -1712,7 +1677,10 @@
    2.90    int fd, isnum;
    2.91    int nfds = 0;
    2.92    fd_set readfds, writefds, exceptfds;
    2.93 -  struct timeval timeout = {0, };
    2.94 +  struct timespec timeout = {0, };
    2.95 +  int use_timeout = 0;
    2.96 +  int check_sigterm = 0;
    2.97 +  sigset_t mask, orig_mask;
    2.98    int status;
    2.99    FD_ZERO(&readfds);
   2.100    FD_ZERO(&writefds);
   2.101 @@ -1784,13 +1752,31 @@
   2.102        return 2;
   2.103      } else if (isnum && n>=0 && n<100000000) {
   2.104        timeout.tv_sec = n;
   2.105 -      timeout.tv_usec = 1e6 * (n - timeout.tv_sec);
   2.106 +      timeout.tv_nsec = 1e9 * (n - timeout.tv_sec);
   2.107      } else {
   2.108        luaL_argcheck(L, 0, 3, "not a valid timeout");
   2.109      }
   2.110 -    status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
   2.111 -  } else {
   2.112 -    status = select(nfds, &readfds, &writefds, &exceptfds, NULL);
   2.113 +    use_timeout = 1;
   2.114 +  }
   2.115 +  if (!lua_isnoneornil(L, 4)) luaL_checktype(L, 4, LUA_TBOOLEAN);
   2.116 +  check_sigterm = lua_toboolean(L, 4);
   2.117 +  if (check_sigterm) {
   2.118 +    sigemptyset(&mask);
   2.119 +    sigaddset(&mask, SIGTERM);
   2.120 +    sigprocmask(SIG_BLOCK, &mask, &orig_mask);
   2.121 +    if (moonbr_io_sigterm_flag) {
   2.122 +      if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
   2.123 +      lua_pushboolean(L, 0);
   2.124 +      lua_pushliteral(L, "SIGTERM received");
   2.125 +      return 2;
   2.126 +    }
   2.127 +  }
   2.128 +  status = pselect(nfds, &readfds, &writefds, &exceptfds, use_timeout ? &timeout : NULL, check_sigterm ? &orig_mask : NULL);
   2.129 +  if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort();
   2.130 +  if (moonbr_io_sigterm_flag) {
   2.131 +    lua_pushboolean(L, 0);
   2.132 +    lua_pushliteral(L, "SIGTERM received");
   2.133 +    return 2;
   2.134    }
   2.135    if (status == -1) {
   2.136      if (errno == EINTR) {
   2.137 @@ -2026,7 +2012,8 @@
   2.138    {"locallisten", moonbr_io_locallisten},
   2.139    {"tcplisten", moonbr_io_tcplisten},
   2.140    {"exec", moonbr_io_exec},
   2.141 -  {"signalsocket", moonbr_io_signalsocket},
   2.142 +  {"sigterm_setup", moonbr_io_sigterm_setup},
   2.143 +  {"sigterm_received", moonbr_io_sigterm_received},
   2.144    {"getpid", moonbr_io_getpid},
   2.145    {"poll", moonbr_io_poll},
   2.146    {"timeref", moonbr_io_timeref},
   2.147 @@ -2048,13 +2035,6 @@
   2.148  int luaopen_moonbridge_io(lua_State *L) {
   2.149  
   2.150    signal(SIGPIPE, SIG_IGN);  /* generate I/O errors instead of signal 13 */
   2.151 -  {
   2.152 -    int i;
   2.153 -    for (i=0; i<=MOONBR_IO_MAXSIGNUM; i++) {
   2.154 -      moonbr_io_signalfd_read(i) = -1;
   2.155 -      moonbr_io_signalfd_write(i) = -1;
   2.156 -    }
   2.157 -  }
   2.158  
   2.159    lua_newtable(L);  // module
   2.160  
   2.161 @@ -2132,9 +2112,6 @@
   2.162    lua_setfield(L, -3, "signals");
   2.163    lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALS_REGKEY);
   2.164  
   2.165 -  lua_newtable(L);  // signal sockets
   2.166 -  lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_SIGNALSOCKETS_REGKEY);
   2.167 -  
   2.168    luaL_setfuncs(L, moonbr_io_module_funcs, 0);
   2.169    return 1;
   2.170  
     3.1 --- a/moonbridge_io.h	Fri Jun 09 18:33:57 2017 +0200
     3.2 +++ b/moonbridge_io.h	Sun Jun 11 00:02:43 2017 +0200
     3.3 @@ -1,5 +1,6 @@
     3.4  
     3.5  void moonbr_io_pushhandle(lua_State *L, int fd);
     3.6  void moonbr_io_closehandle(lua_State *L, int idx, int reset);
     3.7 +int moonbr_io_sigterm_setup(lua_State *L);
     3.8  int luaopen_moonbridge_io(lua_State *L);
     3.9  
     4.1 --- a/reference.txt	Fri Jun 09 18:33:57 2017 +0200
     4.2 +++ b/reference.txt	Sun Jun 11 00:02:43 2017 +0200
     4.3 @@ -377,7 +377,7 @@
     4.4  nil (as first return value) plus an error message (as second return value).
     4.5  
     4.6  
     4.7 -### moonbridge_io.poll(input_set, output_set, timeout)
     4.8 +### moonbridge_io.poll(input_set, output_set, timeout, wakeup_on_sigterm)
     4.9  
    4.10  This function waits for at least one of the given file descriptors and/or
    4.11  I/O handles to be ready for input or output. The two sets of file descriptors
    4.12 @@ -385,9 +385,15 @@
    4.13  which does evaluate to true, e.g. input_set = {[socketA] = true}. If a set is
    4.14  nil, it is treated as being empty.
    4.15  
    4.16 +Returns false (plus a notice as second return value) in case of timeout. If the
    4.17 +4th parameter is set to true, also returns false (plus a notice) when a SIGTERM
    4.18 +has been received since a corresponding signal handler has been installed with
    4.19 +moonbridge_io.sigterm_setup().
    4.20 +
    4.21  Returns true when at least one file descriptor or handle is ready for reading
    4.22 -or writing respectively, or if a signal has been received during waiting.
    4.23 -Returns false (plus a notice as second return value) in case of timeout.
    4.24 +or writing respectively. The function may also return true if signals have been
    4.25 +received during waiting (unless the 4th parameter is set to true and a SIGTERM
    4.26 +was received).
    4.27  
    4.28  
    4.29  ### moonbridge_io.signals
    4.30 @@ -396,17 +402,19 @@
    4.31  number (e.g. 9 or 15, respectively).
    4.32  
    4.33  
    4.34 -### moonbridge_io.signalsocket(signal)
    4.35 +### moonbridge_io.sigterm_received()
    4.36  
    4.37 -This function installs a signal handler. As argument, either the signal number
    4.38 -is passed (e.g. 15) or a name (e.g. "TERM"). The function returns a socket
    4.39 -object that receives a character (".") each time a signal is received.
    4.40 +Returns true if a SIGTERM was received after moonbridge_io.sigterm_setup() has
    4.41 +installed a corresponding signal handler. The function will then always return
    4.42 +true until the process terminates.
    4.43 +
    4.44  
    4.45 -The function can be called multiple times, in which case the same socket object
    4.46 -is returned. The returned socket should never be closed by the caller.
    4.47 +### moonbridge_io.sigterm_setup()
    4.48  
    4.49 -The process should not be forked after calling this function (except for
    4.50 -replacing the process with another program).
    4.51 +This function installs a signal handler for SIGTERM. Use the function
    4.52 +moonbridge_io.sigterm_received() to check whether the signal has been received.
    4.53 +In addition, moonbridge_io.poll(...) will wakeup prematurely if the
    4.54 +4th parameter is set to true.
    4.55  
    4.56  
    4.57  ### moonbridge_io.tcpconnect(hostname, port)

Impressum / About Us