From 15980d0df140bbdf16b83a7b4eee8e6188a297d4 Mon Sep 17 00:00:00 2001
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
Date: Thu, 17 Mar 2022 00:56:55 +0100
Subject: [PATCH] fiber: fix ignorance of flags for reused fibers

fiber_new_ex() used to ignore fiber_attr flags when the fiber was
taken from the cache, not created anew.

It didn't matter much though for the public API, because the only
public flag in fiber_attr was FIBER_CUSTOM_STACK (which can be
set via fiber_attr_setstacksize()).

Anyway that was a bug for internal API and would lead to issues in
the future when more public flags are added. The patch fixes it.

NO_DOC=Bugfix
NO_CHANGELOG=No reproducer via public API

(cherry picked from commit 31d2759942dd0998286c1d20bd1db5db09c02c99)
---
 src/lib/core/fiber.c   |  4 +---
 test/unit/fiber.cc     | 32 ++++++++++++++++++++++++++++++++
 test/unit/fiber.result |  2 ++
 3 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index f7816d780c..9e5a6b93ef 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -1240,7 +1240,6 @@ fiber_new_ex(const char *name, const struct fiber_attr *fiber_attr,
 					  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);
@@ -1265,11 +1264,10 @@ fiber_new_ex(const char *name, const struct fiber_attr *fiber_attr,
 		rlist_create(&fiber->wake);
 		diag_create(&fiber->diag);
 		fiber_reset(fiber);
-		fiber->flags = fiber_attr->flags;
 
 		rlist_add_entry(&cord->alive, fiber, link);
 	}
-
+	fiber->flags = fiber_attr->flags;
 	fiber->f = f;
 	/* Excluding reserved range */
 	if (++cord->max_fid < FIBER_ID_MAX_RESERVED)
diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc
index 9d21840dd1..211a1e8343 100644
--- a/test/unit/fiber.cc
+++ b/test/unit/fiber.cc
@@ -37,6 +37,14 @@ cancel_f(va_list ap)
 	return 0;
 }
 
+static int
+wait_cancel_f(va_list ap)
+{
+	while (!fiber_is_cancelled())
+		fiber_yield();
+	return 0;
+}
+
 static int
 exception_f(va_list ap)
 {
@@ -261,6 +269,29 @@ fiber_dead_while_in_cache_test(void)
 	footer();
 }
 
+static void
+fiber_flags_respect_test(void)
+{
+	header();
+
+	/* Make sure the cache has at least one fiber. */
+	struct fiber *f = fiber_new_xc("nop", noop_f);
+	fiber_start(f);
+
+	/* Fibers taken from the cache need to respect the passed flags. */
+	struct fiber_attr attr;
+	fiber_attr_create(&attr);
+	uint32_t flags = FIBER_IS_JOINABLE | FIBER_IS_CANCELLABLE;
+	attr.flags |= flags;
+	f = fiber_new_ex("wait_cancel", &attr, wait_cancel_f);
+	fail_unless((f->flags & flags) == flags);
+	fiber_wakeup(f);
+	fiber_cancel(f);
+	fiber_join(f);
+
+	footer();
+}
+
 static int
 main_f(va_list ap)
 {
@@ -269,6 +300,7 @@ main_f(va_list ap)
 	fiber_stack_test();
 	fiber_wakeup_self_test();
 	fiber_dead_while_in_cache_test();
+	fiber_flags_respect_test();
 	ev_break(loop(), EVBREAK_ALL);
 	return 0;
 }
diff --git a/test/unit/fiber.result b/test/unit/fiber.result
index 8234bf0e54..61ff54529c 100644
--- a/test/unit/fiber.result
+++ b/test/unit/fiber.result
@@ -21,3 +21,5 @@ SystemError Failed to allocate 42 bytes in allocator for exception: Cannot alloc
 	*** fiber_wakeup_self_test: done ***
 	*** fiber_dead_while_in_cache_test ***
 	*** fiber_dead_while_in_cache_test: done ***
+	*** fiber_flags_respect_test ***
+	*** fiber_flags_respect_test: done ***
-- 
GitLab