diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index 0d92c8d517f6c4e2a8bea7aa9427f34c2e12ebac..99b521d0499c76825065e9d8c69d5e20722b9f11 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -2623,6 +2623,26 @@ procedures. </listitem> </varlistentry> + <varlistentry> + <term> + <emphasis role="lua" xml:id="box.fiber.kill">box.fiber.kill(<replaceable>id</replaceable>) </emphasis> + </term> + <listitem> + <para> + Locate a fiber by its numeric id and cancel it. In + other words, combines <emphasis + role="lua">box.fiber.find()</emphasis> and <emphasis + role="lua">box.fiber.cancel()</emphasis> into one + </para> + <para> + Parameters: <code>id</code> = the id of the fiber to be cancelled. + </para> + <para> + Possible errors: the specified fiber does not exist or does not permit cancel. + </para> + </listitem> + </varlistentry> + <varlistentry> <term> <emphasis role="lua" xml:id="box.fiber.testcancel">box.fiber.testcancel()</emphasis> diff --git a/src/lua/init.cc b/src/lua/init.cc index c6a5400c4fb4a21624ea3b5bb3b19d456f879574..1c1d78eb872ef74150323de4ed721ae1c4338e71 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -917,6 +917,26 @@ lbox_fiber_cancel(struct lua_State *L) return 0; } +/** + * Running and suspended fibers can be cancelled. + * Zombie fibers can't. + */ +static int +lbox_fiber_kill(struct lua_State *L) +{ + if (lua_gettop(L) != 1) + luaL_error(L, "fiber.kill(): bad arguments"); + int fid = lua_tointeger(L, -1); + struct fiber *f = fiber_find(fid); + if (f == NULL) + luaL_error(L, "fiber.kill(): fiber not found"); + if (! (f->flags & FIBER_USER_MODE)) + luaL_error(L, "fiber.kill(): subject fiber does " + "not permit cancel"); + fiber_cancel(f); + return 0; +} + /** * Check if this current fiber has been cancelled and * throw an exception if this is the case. @@ -947,6 +967,7 @@ static const struct luaL_reg fiberlib[] = { {"id", lbox_fiber_id}, {"find", lbox_fiber_find}, {"cancel", lbox_fiber_cancel}, + {"kill", lbox_fiber_kill}, {"testcancel", lbox_fiber_testcancel}, {"create", lbox_fiber_create}, {"resume", lbox_fiber_resume}, diff --git a/test/box/fiber.result b/test/box/fiber.result index 094c0e0ac3e18439787970b61b9147c80255110b..22a312b761e84fec4eafc8c51d697803f61772ec 100644 --- a/test/box/fiber.result +++ b/test/box/fiber.result @@ -330,3 +330,18 @@ lua box.fiber.find(fib_id) --- - nil ... +lua function y() print('started') while true do box.replace(0, 'test', os.time()) box.fiber.sleep(0.001) end end +--- +... +lua f = box.fiber.wrap(y) +--- +... +lua box.fiber.kill(f:id()) +--- +... +lua while box.fiber.status(f) ~= 'dead' do box.fiber.sleep(0.01) end +--- +... +lua box.space[0]:truncate() +--- +... diff --git a/test/box/fiber.test b/test/box/fiber.test index fdbcd90d4999096dad6c2d51d3a3e4ee2644ee8c..79894c65404e1715e7f6560e74cbb23f67d8ef80 100644 --- a/test/box/fiber.test +++ b/test/box/fiber.test @@ -107,3 +107,9 @@ exec admin "lua f:resume()" exec admin "lua fib_id = box.fiber.wrap(testfun):id()" exec admin "lua box.fiber.find(fib_id):cancel()" exec admin "lua box.fiber.find(fib_id)" +# gh-125 box.fiber.cancel() by numeric id +exec admin "lua function y() print('started') while true do box.replace(0, 'test', os.time()) box.fiber.sleep(0.001) end end" +exec admin "lua f = box.fiber.wrap(y)" +exec admin "lua box.fiber.kill(f:id())" +exec admin "lua while box.fiber.status(f) ~= 'dead' do box.fiber.sleep(0.01) end" +exec admin "lua box.space[0]:truncate()"