From 3a851430a19cb78fe5b93736cf96dbe4a8878a7e Mon Sep 17 00:00:00 2001
From: Serge Petrenko <sergepetrenko@tarantool.org>
Date: Wed, 6 Feb 2019 14:23:57 +0300
Subject: [PATCH] Fix tarantool -e "os.exit()" hang

After the patch which made os.exit() execute on_shutdown triggers
(see commit 6dc4c8d7b5b40d66fe0451ef4d1f4bdf4d2cf60e) we relied
on on_shutdown triggers to break the ev_loop and exit tarantool.
Hovewer, there is an auxiliary event loop which is run in
tarantool_lua_run_script() to reschedule the fiber executing chunks
of code passed by -e option and executing interactive mode.
This event loop is started only to execute interactive mode, and
doesn't exist during execution of -e chunks. Make sure we don't start
it if os.exit() was already executed in one of the chunks.

Closes #3966
---
 src/lua/init.c           | 3 ++-
 test/box-py/args.result  | 6 ++++++
 test/box-py/args.test.py | 6 ++++--
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/lua/init.c b/src/lua/init.c
index ca4b47f3a0..d18c8af94a 100644
--- a/src/lua/init.c
+++ b/src/lua/init.c
@@ -664,7 +664,8 @@ tarantool_lua_run_script(char *path, bool interactive,
 	 * Run an auxiliary event loop to re-schedule run_script fiber.
 	 * When this fiber finishes, it will call ev_break to stop the loop.
 	 */
-	ev_run(loop(), 0);
+	if (start_loop)
+		ev_run(loop(), 0);
 	/* The fiber running the startup script has ended. */
 	script_fiber = NULL;
 }
diff --git a/test/box-py/args.result b/test/box-py/args.result
index fe9ac3448b..54629edea5 100644
--- a/test/box-py/args.result
+++ b/test/box-py/args.result
@@ -118,6 +118,12 @@ Compiler: cc
 C_FLAGS: flags
 CXX_FLAGS: flags
 
+tarantool -e print(1) os.exit() print(2)
+1
+
+tarantool -e print(1) -e os.exit() -e print(1) -e os.exit() -e print(1)
+1
+
 tarantool -e print('Hello') ${SOURCEDIR}/test/box-py/args.lua 1 2 3
 Hello
 arg[-1] => tarantool
diff --git a/test/box-py/args.test.py b/test/box-py/args.test.py
index ab6f8f2e7c..f89c5bb094 100644
--- a/test/box-py/args.test.py
+++ b/test/box-py/args.test.py
@@ -37,6 +37,10 @@ server.test_option(script + " 1 2 3 --help")
 server.test_option(script + " --help 1 2 3")
 server.test_option("-V " + script + " 1 2 3")
 
+# gh-3966: os.exit() hangs if called by a command from the argument list.
+server.test_option("-e \"print(1) os.exit() print(2)\"")
+server.test_option("-e \"print(1)\" -e \"os.exit()\" -e \"print(1)\" -e \"os.exit()\" -e \"print(1)\"")
+
 server.test_option("-e \"print('Hello')\" " + script + " 1 2 3")
 server.test_option("-e \"a = 10\" " + \
                    "-e print(a) " + \
@@ -50,5 +54,3 @@ server.test_option("-e \"print(rawget(_G, 'log') == nil)\" " + \
                    " 1 2 3 --help")
 
 sys.stdout.clear_all_filters()
-# Args filter cleanup
-# vim: syntax=python
-- 
GitLab