# HG changeset patch # User jbe # Date 1497145828 -7200 # Node ID 524bb61496b544f495baae51e77f18e320a7d4b6 # Parent 2fe69234cbe95dc7af8e698a273d2133ec33dbd8 Changed behavior of moonbridge_io.poll(...); Renamed moonbridge_io.sigterm_setup() to moonbridge_io.catch_sigterm(); Removed moonbridge_io.sigterm_received() diff -r 2fe69234cbe9 -r 524bb61496b5 moonbridge.c --- a/moonbridge.c Sun Jun 11 01:27:52 2017 +0200 +++ b/moonbridge.c Sun Jun 11 03:50:28 2017 +0200 @@ -755,7 +755,7 @@ char controlmsg; int fd; struct itimerval notimer = { { 0, }, { 0, } }; - moonbr_io_sigterm_setup(L); // NOTE: should not fail + moonbr_io_catch_sigterm(L); // NOTE: should not fail lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); if (lua_isnil(L, -1)) lua_pop(L, 1); else if (lua_pcall(L, 0, 0, 1)) { diff -r 2fe69234cbe9 -r 524bb61496b5 moonbridge_http.lua --- a/moonbridge_http.lua Sun Jun 11 01:27:52 2017 +0200 +++ b/moonbridge_http.lua Sun Jun 11 03:50:28 2017 +0200 @@ -1094,11 +1094,13 @@ return true -- success end -- wait for input: - if not poll(socket_set, nil, idle_timeout, true) then - if moonbridge_io.sigterm_received() then + local ready, pollmsg, quit = poll(socket_set, nil, idle_timeout, true) + if not ready then + if quit then return request_error(false, "408 Request Timeout", "Server shutdown") + else + return request_error(false, "408 Request Timeout", "Idle connection timed out") end - return request_error(false, "408 Request Timeout", "Idle connection timed out") end -- read headers (with timeout): do diff -r 2fe69234cbe9 -r 524bb61496b5 moonbridge_io.c --- a/moonbridge_io.c Sun Jun 11 01:27:52 2017 +0200 +++ b/moonbridge_io.c Sun Jun 11 03:50:28 2017 +0200 @@ -1615,16 +1615,11 @@ moonbr_io_sigterm_flag = 1; } -int moonbr_io_sigterm_setup(lua_State *L) { +int moonbr_io_catch_sigterm(lua_State *L) { signal(SIGTERM, moonbr_io_sigterm_handler); return 0; } -static int moonbr_io_sigterm_received(lua_State *L) { - lua_pushboolean(L, moonbr_io_sigterm_flag); - return 1; -} - static int moonbr_io_getpid(lua_State *L) { lua_pushinteger(L, getpid()); return 1; @@ -1666,7 +1661,7 @@ int nfds = 0; fd_set readfds, writefds, exceptfds; struct timespec timeout = {0, }; - int use_timeout = 0; + int use_timeout = 0; // negative for negative timeout int check_sigterm = 0; sigset_t mask, orig_mask; int status; @@ -1735,36 +1730,50 @@ lua_Number n; n = lua_tonumberx(L, 3, &isnum); if (isnum && n<0) { - lua_pushboolean(L, 0); - lua_pushliteral(L, "Negative timeout"); - return 2; + use_timeout = -1; } else if (isnum && n>=0 && n<100000000) { + use_timeout = 1; timeout.tv_sec = n; timeout.tv_nsec = 1e9 * (n - timeout.tv_sec); } else { luaL_argcheck(L, 0, 3, "not a valid timeout"); } - use_timeout = 1; } if (!lua_isnoneornil(L, 4)) luaL_checktype(L, 4, LUA_TBOOLEAN); check_sigterm = lua_toboolean(L, 4); if (check_sigterm) { sigemptyset(&mask); sigaddset(&mask, SIGTERM); - sigprocmask(SIG_BLOCK, &mask, &orig_mask); + if (use_timeout >= 0) sigprocmask(SIG_BLOCK, &mask, &orig_mask); if (moonbr_io_sigterm_flag) { - if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort(); + if (use_timeout >= 0) if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort(); lua_pushboolean(L, 0); lua_pushliteral(L, "SIGTERM received"); + lua_pushboolean(L, 1); + return 3; + } + } + if (use_timeout < 0) { + lua_pushboolean(L, 0); + lua_pushliteral(L, "Negative timeout"); + if (check_sigterm) { + lua_pushboolean(L, 0); + return 3; + } else { return 2; } } - status = pselect(nfds, &readfds, &writefds, &exceptfds, use_timeout ? &timeout : NULL, check_sigterm ? &orig_mask : NULL); + status = pselect( + nfds, &readfds, &writefds, &exceptfds, + use_timeout ? &timeout : NULL, + check_sigterm ? &orig_mask : NULL + ); if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) abort(); - if (moonbr_io_sigterm_flag) { + if (check_sigterm && moonbr_io_sigterm_flag) { lua_pushboolean(L, 0); lua_pushliteral(L, "SIGTERM received"); - return 2; + lua_pushboolean(L, 1); + return 3; } if (status == -1) { if (errno == EINTR) { @@ -1776,8 +1785,13 @@ } } else if (status == 0) { lua_pushboolean(L, 0); - lua_pushliteral(L, "Timeout while polling file descriptors"); - return 2; + lua_pushliteral(L, "Timeout while waiting for I/O"); + if (check_sigterm) { + lua_pushboolean(L, 0); + return 3; + } else { + return 2; + } } else { lua_pushboolean(L, 1); return 1; @@ -2000,8 +2014,7 @@ {"locallisten", moonbr_io_locallisten}, {"tcplisten", moonbr_io_tcplisten}, {"exec", moonbr_io_exec}, - {"sigterm_setup", moonbr_io_sigterm_setup}, - {"sigterm_received", moonbr_io_sigterm_received}, + {"catch_sigterm", moonbr_io_catch_sigterm}, {"getpid", moonbr_io_getpid}, {"poll", moonbr_io_poll}, {"timeref", moonbr_io_timeref}, diff -r 2fe69234cbe9 -r 524bb61496b5 moonbridge_io.h --- a/moonbridge_io.h Sun Jun 11 01:27:52 2017 +0200 +++ b/moonbridge_io.h Sun Jun 11 03:50:28 2017 +0200 @@ -1,6 +1,6 @@ void moonbr_io_pushhandle(lua_State *L, int fd); void moonbr_io_closehandle(lua_State *L, int idx, int reset); -int moonbr_io_sigterm_setup(lua_State *L); +int moonbr_io_catch_sigterm(lua_State *L); int luaopen_moonbridge_io(lua_State *L); diff -r 2fe69234cbe9 -r 524bb61496b5 reference.txt --- a/reference.txt Sun Jun 11 01:27:52 2017 +0200 +++ b/reference.txt Sun Jun 11 03:50:28 2017 +0200 @@ -299,6 +299,15 @@ listed below. +### moonbridge_io.catch_sigterm() + +This function installs a signal handler for SIGTERM. Instead of causing +immediate process termination, the behavior of moonbridge_io.poll(...) is +modified. + +See moonbridge_io.poll(...) for further information. + + ### moonbridge_io.exec(command, arg1, arg2, ...) Executes the given command and returns a handle with three sockets named @@ -390,35 +399,34 @@ which does evaluate to true, e.g. input_set = {[socketA] = true}. If a set is nil, it is treated as being empty. -Returns false (plus a notice as second return value) in case of timeout. If the -4th parameter is set to true, also returns false (plus a notice) when a SIGTERM -has been received since a corresponding signal handler has been installed with -moonbridge_io.sigterm_setup(). +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. + +The function returns true when at least one file descriptor or handle is ready +for reading or writing respectively. The function may also return true (for +technical reasons) if signals other than SIGTERM have been received during +waiting. -Returns true when at least one file descriptor or handle is ready for reading -or writing respectively. The function may also return true if signals have been -received during waiting (unless the 4th parameter is set to true and a SIGTERM -was received). +If the 4th parameter (wakeup_on_sigterm) is omitted or set to false, then the +function only returns false as first return value if a timeout happened. In +this case, the second return value will be set to an appropriate message string +such that assert(moonbridge_io.poll(...)) can be used to throw an error. + +If the 4th parameter (wakeup_on_sigterm) is set to true, then three values are +returned if a timeout happened or a SIGTERM has been received: false as first +return value, a message string as second return value (that may, for example, +be used for assert(...)), and a boolean as third return value which indicates +whether the function prematurely returned because of SIGTERM. + +this case a corresponding message will be provided as second return value such +that it is possible to call assert(moonbride_io.poll(...)) to raise an error if +a timeout occurs. Note that the function is not thread-safe when the 4th parameter is set to true. -### moonbridge_io.sigterm_received() - -Returns true if a SIGTERM was received after moonbridge_io.sigterm_setup() has -installed a corresponding signal handler. The function will then always return -true until the process terminates. - - -### moonbridge_io.sigterm_setup() - -This function installs a signal handler for SIGTERM. Use the function -moonbridge_io.sigterm_received() to check whether the signal has been received. -In addition, moonbridge_io.poll(...) will wakeup prematurely if the -4th parameter is set to true. - - ### moonbridge_io.tcpconnect(hostname, port) Tries to open a TCP connection with the given host and TCP port number. Returns