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)