From 8b380c93f66db25af7749e923c6d35c0af87c448 Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Thu, 2 Oct 2014 18:21:27 +0400
Subject: [PATCH] Fix #334: Warnings on startup

Tarantool's signal handlers are now installed *before* executing
Lua script. libreadline doesn't install own signals anymore.
TTY is now clean up properly in all cases.

This patch also fixes possible problems with signal handlers
after daemonization via box.cfg { background = true }.
---
 src/lua/init.cc  | 20 ++++++++++++++++++++
 src/tarantool.cc | 35 ++++++++++++++++++++++-------------
 2 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/src/lua/init.cc b/src/lua/init.cc
index 02fa51d7e6..17d3cc78f5 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 c7c4830871..138e66611e 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) {
-- 
GitLab