From 132cb94bf1cf20c8bff4f8fe35a788c94943128e Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Thu, 21 Nov 2013 20:16:12 +0400
Subject: [PATCH] A fix and a test case for gh-131

Fix a hang on box.fiber.resume() of an attached fiber which gets
cancelled.
When the child fiber got cancelled before detach, the parent
never was woken up, and would hang forever.
Wake up the parent, and, in the parent, do not try to access
a dead fiber.
---
 src/lua/init.cc       | 11 +++++++++--
 test/box/fiber.result | 10 ++++++++++
 test/box/fiber.test   |  5 +++++
 3 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/lua/init.cc b/src/lua/init.cc
index 8282ef1ef8..11b6e4cfdd 100644
--- a/src/lua/init.cc
+++ b/src/lua/init.cc
@@ -517,6 +517,10 @@ box_lua_fiber_run(va_list ap __attribute__((unused)))
 
 		cleanup();
 	} catch (const FiberCancelException& e) {
+		if (box_lua_fiber_get_coro(L, fiber)) {
+			struct fiber *caller = box_lua_fiber_get_caller(L);
+			fiber_wakeup(caller);
+		}
 		box_lua_fiber_clear_coro(tarantool_L, fiber);
 		/*
 		 * Note: FiberCancelException leaves garbage on
@@ -638,14 +642,17 @@ lbox_fiber_resume(struct lua_State *L)
 	 */
 	fiber_yield_to(f);
 	/*
-	 * The called fiber could have done only 3 things:
+	 * The called fiber could have done 4 things:
 	 * - yielded to us (then we should grab its return)
 	 * - completed (grab return values, wake up the fiber,
 	 *   so that it can die)
 	 * - detached (grab return values, wakeup the fiber so it
 	 *   can continue).
+	 * - got cancelled (return)
 	 */
-	assert(f->fid == fid);
+	if (f->fid != fid)
+		luaL_error(L, "fiber.resume(): the child fiber got cancelled");
+
 	tarantool_lua_set_out(child_L, NULL);
 	/* Find out the state of the child fiber. */
 	enum fiber_state child_state = (enum fiber_state) lua_tointeger(child_L, -1);
diff --git a/test/box/fiber.result b/test/box/fiber.result
index 41209e7f0c..684ca93c6d 100644
--- a/test/box/fiber.result
+++ b/test/box/fiber.result
@@ -209,3 +209,13 @@ lua box.fiber.find('test')
 ---
  - nil
 ...
+lua f = box.fiber.create(function() box.fiber.cancel(box.fiber.self()) end)
+---
+...
+lua box.fiber.resume(f)
+---
+error: 'fiber.resume(): the child fiber got cancelled'
+...
+lua f = nil
+---
+...
diff --git a/test/box/fiber.test b/test/box/fiber.test
index 3d3e92a19d..491005c4b9 100644
--- a/test/box/fiber.test
+++ b/test/box/fiber.test
@@ -83,3 +83,8 @@ exec admin "lua box.space[0]:truncate()"
 # https://github.com/tarantool/tarantool/issues/33
 exec admin "lua box.fiber.find()"
 exec admin "lua box.fiber.find('test')"
+# https://github.com/tarantool/tarantool/issues/131
+# box.fiber.resume(box.fiber.cancel()) -- hang
+exec admin "lua f = box.fiber.create(function() box.fiber.cancel(box.fiber.self()) end)"
+exec admin "lua box.fiber.resume(f)"
+exec admin "lua f = nil"
-- 
GitLab