diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index 08087cfe46586cba582f66f08b5b98f40d099db7..3acdef6c87526428ef2fae53f73db43b3fcef9b4 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -528,14 +528,19 @@ fiber_wakeup(struct fiber *f) void fiber_cancel(struct fiber *f) { - assert(f->fid != 0); /** * Do nothing if the fiber is dead, since cancelling * the fiber would clear the diagnostics area and * the cause of death would be lost. */ - if (fiber_is_dead(f)) + if (fiber_is_dead(f)) { + if ((f->flags & FIBER_IS_JOINABLE) == 0) { + panic("Cancel of a finished and already " + "recycled fiber"); + } + assert(f->fid != 0); return; + } f->flags |= FIBER_IS_CANCELLED; @@ -662,6 +667,9 @@ fiber_join_timeout(struct fiber *fiber, double timeout) diag_set(TimedOut); return -1; } + assert((fiber->flags & FIBER_IS_RUNNING) == 0); + assert((fiber->flags & FIBER_IS_JOINABLE) != 0); + fiber->flags &= ~FIBER_IS_JOINABLE; /* Move exception to the caller */ int ret = fiber->f_ret; @@ -877,11 +885,6 @@ fiber_reset(struct fiber *fiber) { rlist_create(&fiber->on_yield); rlist_create(&fiber->on_stop); - /* - * Preserve the running flag if set. Reset might be called on the - * current fiber when it is recycled. - */ - fiber->flags = FIBER_DEFAULT_FLAGS | (fiber->flags & FIBER_IS_RUNNING); #if ENABLE_FIBER_TOP clock_stat_reset(&fiber->clock_stat); #endif /* ENABLE_FIBER_TOP */ @@ -891,6 +894,7 @@ fiber_reset(struct fiber *fiber) static void fiber_recycle(struct fiber *fiber) { + assert((fiber->flags & FIBER_IS_DEAD) != 0); /* no exceptions are leaking */ assert(diag_is_empty(&fiber->diag)); /* no pending wakeup */ @@ -1237,6 +1241,8 @@ fiber_new_ex(const char *name, const struct fiber_attr *fiber_attr, fiber = rlist_first_entry(&cord->dead, struct fiber, link); rlist_move_entry(&cord->alive, fiber, link); + assert((fiber->flags | FIBER_IS_DEAD) != 0); + fiber->flags = FIBER_DEFAULT_FLAGS; } else { fiber = (struct fiber *) mempool_alloc(&cord->fiber_mempool); @@ -1478,7 +1484,7 @@ cord_create(struct cord *cord, const char *name) cord->sched.name = NULL; fiber_set_name(&cord->sched, "sched"); cord->fiber = &cord->sched; - cord->sched.flags |= FIBER_IS_RUNNING; + cord->sched.flags = FIBER_IS_RUNNING; cord->next_fid = FIBER_ID_MAX_RESERVED + 1; /* diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc index c0a46c6123c282e644bd3ffe28b457a60dba5579..9d21840dd1f646f04c9b7ec1e9ae01a4e233f9d6 100644 --- a/test/unit/fiber.cc +++ b/test/unit/fiber.cc @@ -246,6 +246,21 @@ fiber_wakeup_self_test() footer(); } +static void +fiber_dead_while_in_cache_test(void) +{ + header(); + + struct fiber *f = fiber_new_xc("nop", noop_f); + int fiber_count = fiber_count_total(); + fiber_start(f); + /* The fiber remains in the cache of recycled fibers. */ + fail_unless(fiber_count == fiber_count_total()); + fail_unless(fiber_is_dead(f)); + + footer(); +} + static int main_f(va_list ap) { @@ -253,6 +268,7 @@ main_f(va_list ap) fiber_join_test(); fiber_stack_test(); fiber_wakeup_self_test(); + fiber_dead_while_in_cache_test(); ev_break(loop(), EVBREAK_ALL); return 0; } diff --git a/test/unit/fiber.result b/test/unit/fiber.result index 320b258f5f446d7639e072db747129cd2c7ce19b..f85d7aca899a5c84fc05cf47b0c992c8f6a8857c 100644 --- a/test/unit/fiber.result +++ b/test/unit/fiber.result @@ -19,3 +19,5 @@ OutOfMemory: Failed to allocate 42 bytes in allocator for exception *** fiber_stack_test: done *** *** fiber_wakeup_self_test *** *** fiber_wakeup_self_test: done *** + *** fiber_dead_while_in_cache_test *** + *** fiber_dead_while_in_cache_test: done ***