diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index d133ddcccb81f7ca75459127d0a77d162ed402d9..ba0715616359055c5be02ff69552672f6f27770a 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -2357,6 +2357,12 @@ fiber_set_system(struct fiber *f, bool yesno) } } +void +fiber_set_managed_shutdown(struct fiber *f) +{ + f->flags |= FIBER_MANAGED_SHUTDOWN; +} + int fiber_shutdown(double timeout) { @@ -2364,6 +2370,8 @@ fiber_shutdown(double timeout) cord()->is_shutdown = true; struct fiber *fiber; rlist_foreach_entry(fiber, &cord()->alive, link) { + if (fiber->flags & FIBER_MANAGED_SHUTDOWN) + fiber_set_system(fiber, false); if (!(fiber->flags & FIBER_IS_SYSTEM)) fiber_cancel(fiber); } diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h index 2f0885ba60512f7b2172e5f56897bc108a503512..4abdb92847e8fb9963c2c0f2c31bc5687df96e74 100644 --- a/src/lib/core/fiber.h +++ b/src/lib/core/fiber.h @@ -175,6 +175,11 @@ enum { * once again nor can its joinability be changed. */ FIBER_JOIN_BEEN_INVOKED = 1 << 9, + /** + * Makes sense only for system fibers. If flag is set then fiber + * will be finished on fiber_shutdown(). + */ + FIBER_MANAGED_SHUTDOWN = 1 << 10, FIBER_DEFAULT_FLAGS = 0 }; @@ -1245,6 +1250,14 @@ fiber_lua_state(struct fiber *f); void fiber_set_system(struct fiber *f, bool yesno); +/** + * Turn managed shutdown on for system fiber. See FIBER_MANAGED_SHUTDOWN. + * It is should be used after fiber creation. Using it during shutdown does not + * work. + */ +void +fiber_set_managed_shutdown(struct fiber *f); + /** * Cancel all client (non system) fibers and wait until they finished. * diff --git a/src/lua/fiber.c b/src/lua/fiber.c index 88ea0fad35419b2e07b65877b771e6b9136c3daf..d66f59d314e41446958bee302457bee3345d620a 100644 --- a/src/lua/fiber.c +++ b/src/lua/fiber.c @@ -938,6 +938,20 @@ lbox_fiber_set_system(struct lua_State *L) return 0; } +/** Turn managed shutdown for fiber. Takes the fiber as single argument. */ +static int +lbox_fiber_set_managed_shutdown(struct lua_State *L) +{ + if (lua_gettop(L) != 1) { + diag_set(IllegalParams, + "fiber.set_managed_shutdown(id): bad arguments"); + luaT_error(L); + } + struct fiber *fiber = lbox_checkfiber(L, 1); + fiber_set_managed_shutdown(fiber); + return 0; +} + /** Helper for fiber slice parsing. */ static struct fiber_slice lbox_fiber_slice_parse(struct lua_State *L, int idx) @@ -1085,6 +1099,7 @@ static const struct luaL_Reg fiberlib[] = { /* Internal functions, to hide in fiber.lua. */ {"stall", lbox_fiber_stall}, {"set_system", lbox_fiber_set_system}, + {"set_managed_shutdown", lbox_fiber_set_managed_shutdown}, {NULL, NULL} }; diff --git a/src/lua/fiber.lua b/src/lua/fiber.lua index 48eda368add5746260531311c840834a8faf50cd..44470e8043ae914c284857cd9f2d4f159c28bc5f 100644 --- a/src/lua/fiber.lua +++ b/src/lua/fiber.lua @@ -74,8 +74,10 @@ fiber.clock64 = fiber_clock64 local stall = fiber.stall local fiber_set_system = fiber.set_system +local fiber_set_managed_shutdown = fiber.set_managed_shutdown fiber.stall = nil fiber.set_system = nil +fiber.set_managed_shutdown = nil local worker_next_task = nil local worker_last_task @@ -134,6 +136,7 @@ end fiber._internal = fiber._internal or {} fiber._internal.schedule_task = worker_schedule_task fiber._internal.set_system = fiber_set_system +fiber._internal.set_managed_shutdown = fiber_set_managed_shutdown setmetatable(fiber, {__serialize = function(self) local res = table.copy(self) diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc index 36cd59b7420e895f29de97b1de82e5fd38c148df..5daf5975296d11074b4025b6b64cf4fe9b87632f 100644 --- a/test/unit/fiber.cc +++ b/test/unit/fiber.cc @@ -695,6 +695,10 @@ fiber_test_shutdown(void) struct fiber *fiber4 = fiber_new("fiber4", new_fiber_on_shudown_f); fail_unless(fiber4 != NULL); fiber_set_joinable(fiber4, true); + struct fiber *fiber6 = fiber_new_system("fiber6", wait_cancel_f); + fail_unless(fiber6 != NULL); + fiber_set_managed_shutdown(fiber6); + fiber_set_joinable(fiber6, true); int rc = fiber_shutdown(1000.0); fail_unless(rc == 0); @@ -703,9 +707,11 @@ fiber_test_shutdown(void) fail_unless((fiber2->flags & FIBER_IS_DEAD) == 0); fail_unless((fiber3->flags & FIBER_IS_DEAD) == 0); fail_unless((fiber4->flags & FIBER_IS_DEAD) != 0); + fail_unless((fiber6->flags & FIBER_IS_DEAD) != 0); fiber_join(fiber1); fiber_join(fiber4); + fiber_join(fiber6); fiber_set_joinable(fiber2, true); fiber_cancel(fiber2);