diff --git a/src/lua/init.cc b/src/lua/init.cc index 02fa51d7e6f357c9db52882451932aa0264b0a3b..17d3cc78f5b90381bcd840056cee92a83c3d8d68 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -192,6 +192,15 @@ readline_cb(va_list ap) { const char **line = va_arg(ap, const char **); const char *prompt = va_arg(ap, const char *); + /* + * libeio threads blocks all signals by default. Therefore, nobody + * can interrupt read(2) syscall inside readline() to correctly + * cleanup resources and restore terminal state. In case of signal + * a signal_cb(), a ev watcher in tarantool.cc will stop event + * loop and and stop entire process by exiting the main thread. + * rl_cleanup_after_signal() is called from tarantool_lua_free() + * in order to restore terminal state. + */ *line = readline(prompt); return 0; } @@ -303,6 +312,12 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv) luaopen_json(L); lua_pop(L, 1); + /* + * Disable libreadline signals handlers. All signals are handled in + * main thread by libev watchers. + */ + rl_catch_signals = 0; + rl_catch_sigwinch = 0; static const struct luaL_reg consolelib[] = { {"readline", tarantool_console_readline}, {"add_history", tarantool_console_add_history}, @@ -443,5 +458,10 @@ tarantool_lua_free() lua_close(tarantool_L); } tarantool_L = NULL; + + if (isatty(STDIN_FILENO)) { + /* See comments in readline_cb() */ + rl_cleanup_after_signal(); + } } diff --git a/src/tarantool.cc b/src/tarantool.cc index c7c4830871c438ddc61351da2d4ce48f5b52749a..138e66611e2b46cca47ed7b3e9a1d90a0daed2bc 100644 --- a/src/tarantool.cc +++ b/src/tarantool.cc @@ -75,6 +75,7 @@ int main_argc; /** Signals handled after start as part of the event loop. */ static ev_signal ev_sigs[4]; static const int ev_sig_count = sizeof(ev_sigs)/sizeof(*ev_sigs); +static bool start_loop = true; extern const void *opt_def; @@ -153,6 +154,7 @@ signal_cb(ev_loop *loop, struct ev_signal *w, int revents) (void) w; (void) revents; + start_loop = false; /* Terminate the main event loop */ ev_break(loop, EVBREAK_ALL); } @@ -234,13 +236,6 @@ signal_free(void) ev_signal_stop(loop(), &ev_sigs[i]); } -static void -signal_start(void) -{ - for (int i = 0; i < ev_sig_count; i++) - ev_signal_start(loop(), &ev_sigs[i]); -} - /** Make sure the child has a default signal disposition. */ static void signal_reset() @@ -260,6 +255,9 @@ signal_reset() sigaction(SIGFPE, &sa, NULL) == -1) say_syserror("sigaction"); + for (int i = 0; i < ev_sig_count; i++) + ev_signal_stop(loop(), &ev_sigs[i]); + /* Unblock any signals blocked by libev. */ sigset_t sigset; sigfillset(&sigset); @@ -302,6 +300,8 @@ signal_init(void) ev_signal_init(&ev_sigs[1], signal_cb, SIGINT); ev_signal_init(&ev_sigs[2], signal_cb, SIGTERM); ev_signal_init(&ev_sigs[3], signal_cb, SIGHUP); + for (int i = 0; i < ev_sig_count; i++) + ev_signal_start(loop(), &ev_sigs[i]); (void) tt_pthread_atfork(NULL, NULL, signal_reset); } @@ -367,6 +367,12 @@ background() if (setsid() == -1) goto error; + /* + * reinit signals after fork, because fork() implicitly calls + * signal_reset() via pthread_atfork() hook installed by signal_init(). + */ + signal_init(); + /* reinit coeio after fork (because libeio required it) */ coeio_reinit(); /* @@ -610,9 +616,6 @@ main(int argc, char **argv) main_argc = argc; main_argv = argv; - /* main core cleanup routine */ - atexit(tarantool_free); - fiber_init(); /* Init iobuf library with default readahead */ iobuf_init(); @@ -620,7 +623,9 @@ main(int argc, char **argv) signal_init(); tarantool_lua_init(tarantool_bin, main_argc, main_argv); - bool start_loop = false; + /* main core cleanup routine */ + atexit(tarantool_free); + try { int events = ev_activecnt(loop()); /* @@ -630,12 +635,16 @@ main(int argc, char **argv) * initialized. */ tarantool_lua_run_script(script); - start_loop = ev_activecnt(loop()) > events; + /* + * Start event loop after executing Lua script if signal_cb() + * wasn't triggered and there is some new events. Initial value + * of start_loop can be set to false by signal_cb(). + */ + start_loop = start_loop && ev_activecnt(loop()) > events; region_free(&fiber()->gc); if (start_loop) { say_crit("entering the event loop"); ev_now_update(loop()); - signal_start(); ev_run(loop(), 0); } } catch (Exception *e) {