From aae1daabc07592f216c340219bdf10db0645660b Mon Sep 17 00:00:00 2001
From: Igor Munkin <imun@tarantool.org>
Date: Tue, 11 Jul 2023 15:13:38 +0000
Subject: [PATCH] cmake: introduce FIBER_STACK_SIZE option

In scope of the commit 82f4b4a3b1fb ("lib/core/fiber: Increase default
stack size") the default value of fiber stack size is increased up to
512 Kb (you can find the reasons in the aforementioned commit message
and in https://github.com/tarantool/tarantool/issues/3418 description).

Some of the tests in test/PUC-Rio-Lua-5.1-test suite in LuaJIT repo
(e.g. some cases with deep recursion in errors.lua or pm.lua) have
already been tweaked according to the limitations mentioned in
https://github.com/tarantool/tarantool/issues/5782, but the crashes
still occurs while running LuaJIT tests with ASan support enabled.

To make the testing routine more convenient, FIBER_STACK_SIZE option is
introduced to Tarantool CMake machinery. One can provide the size either
by raw digits (i.e. in bytes) or using Kb/Mb suffixes for convenience.

A couple of important nits:
* If the given value is not a multiple of 4Kb, CMake machinery adjusts
  it up to the nearest one greater than this value.
* If the adjusted value is less than 512Kb, configuration fails with the
  corresponding CMake fatal error.

Follows up #3418
Relates to #5782

@TarantoolBot document
Title: introduce FIBER_STACK_SIZE configuration option

To make managing of the default fiber stack size more convenient, the
corresponding CMake option is added.

**NB**: The stack size can't be less than 512Kb and if the given value
is not a multiple of 4Kb, CMake machinery adjusts it up to the nearest
one greater than this value.

(cherry picked from commit ff57f990f359f6d7866c1947174d8ba0e97b1ea6)
---
 CMakeLists.txt                                |  1 +
 .../add-fiber-stack-size-option-to-cmake.md   |  3 ++
 cmake/SetFiberStackSize.cmake                 | 45 +++++++++++++++++++
 src/lib/core/fiber.c                          |  6 ++-
 test/unit/fiber_stack.c                       | 11 ++++-
 5 files changed, 62 insertions(+), 4 deletions(-)
 create mode 100644 changelogs/unreleased/add-fiber-stack-size-option-to-cmake.md
 create mode 100644 cmake/SetFiberStackSize.cmake

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 729c6c3222..18650e8259 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,6 +72,7 @@ include(cmake/module.cmake)
 include(cmake/thread.cmake)
 include(cmake/hardening.cmake)
 include(cmake/prefix.cmake)
+include(cmake/SetFiberStackSize.cmake)
 
 add_compile_flags("C;CXX" ${HARDENING_FLAGS})
 set(DEPENDENCY_CFLAGS "${DEPENDENCY_CFLAGS} ${HARDENING_FLAGS}")
diff --git a/changelogs/unreleased/add-fiber-stack-size-option-to-cmake.md b/changelogs/unreleased/add-fiber-stack-size-option-to-cmake.md
new file mode 100644
index 0000000000..d1804530cb
--- /dev/null
+++ b/changelogs/unreleased/add-fiber-stack-size-option-to-cmake.md
@@ -0,0 +1,3 @@
+## feature/build
+
+* Added the CMake option `FIBER_STACK_SIZE` to set the default fiber stack size.
diff --git a/cmake/SetFiberStackSize.cmake b/cmake/SetFiberStackSize.cmake
new file mode 100644
index 0000000000..78404af023
--- /dev/null
+++ b/cmake/SetFiberStackSize.cmake
@@ -0,0 +1,45 @@
+# This module provides a CMake configuration variable to set
+# fiber stack size. If no value is given the default size equals
+# to 512Kb (see https://github.com/tarantool/tarantool/issues/3418
+# for more info). Possible types of values are described below.
+# The given size is converted to bytes and aligned up to be
+# multiple of 4Kb. As a result the corresponding define value is
+# propagated to the sources.
+
+set(FIBER_STACK_SIZE "524288" CACHE STRING "Fiber stack size")
+
+# Possible values of the stack size:
+# * Just a bunch of digits: the size is given in bytes
+# * Digits with "KB"|"Kb" suffix: the size is given in kilobytes
+# * Digits with "MB"|"Mb" suffix: the size is given in megabytes
+# All other values are considered as invalid.
+if(FIBER_STACK_SIZE MATCHES "^([0-9]+)$")
+    set(FIBER_STACK_SIZE_IN_BYTES ${CMAKE_MATCH_1})
+elseif(FIBER_STACK_SIZE MATCHES "([0-9]+)K[bB]$")
+    math(EXPR FIBER_STACK_SIZE_IN_BYTES "${CMAKE_MATCH_1} << 10")
+elseif(FIBER_STACK_SIZE MATCHES "([0-9]+)M[bB]$")
+    math(EXPR FIBER_STACK_SIZE_IN_BYTES "${CMAKE_MATCH_1} << 20")
+else()
+    message(FATAL_ERROR "Invalid size of the fiber stack")
+endif()
+
+# XXX: Align the stack size in bytes up to be multiple of 4Kb.
+math(EXPR FIBER_STACK_SIZE_IN_BYTES
+    "((${FIBER_STACK_SIZE_IN_BYTES} >> 12) + 1) << 12")
+
+# See the rationale for the minimal fiber stack size in
+# https://github.com/tarantool/tarantool/issues/3418.
+if(FIBER_STACK_SIZE_IN_BYTES LESS 524288)
+    message(FATAL_ERROR "[SetFiberStackSize] Minimal fiber stack size is 512Kb,"
+        " but ${FIBER_STACK_SIZE} is given as a default")
+else()
+    message(STATUS "[SetFiberStackSize] Default fiber stack size: "
+        " ${FIBER_STACK_SIZE} (adjusted to ${FIBER_STACK_SIZE_IN_BYTES} bytes)")
+endif()
+
+# Propagate the value to the sources.
+add_definitions(-DFIBER_STACK_SIZE_DEFAULT=${FIBER_STACK_SIZE_IN_BYTES})
+
+# XXX: Unset variables to avoid spoiliing CMake environment.
+unset(FIBER_STACK_SIZE_IN_BYTES)
+unset(FIBER_STACK_SIZE)
diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index 652737713e..0e281b49b2 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -258,11 +258,13 @@ pthread_t main_thread_id;
 static size_t page_size;
 static int stack_direction;
 
+#ifndef FIBER_STACK_SIZE_DEFAULT
+#error "Default fiber stack size is not set"
+#endif
+
 enum {
 	/* The minimum allowable fiber stack size in bytes */
 	FIBER_STACK_SIZE_MINIMAL = 16384,
-	/* Default fiber stack size in bytes */
-	FIBER_STACK_SIZE_DEFAULT = 524288,
 	/* Stack size watermark in bytes. */
 	FIBER_STACK_SIZE_WATERMARK = 65536,
 };
diff --git a/test/unit/fiber_stack.c b/test/unit/fiber_stack.c
index 8a3740e39a..3c7cf881ce 100644
--- a/test/unit/fiber_stack.c
+++ b/test/unit/fiber_stack.c
@@ -31,15 +31,22 @@ main_f(va_list ap)
 	struct errinj *inj;
 	struct fiber *fiber;
 	int fiber_count = fiber_count_total();
+	struct fiber_attr *fiber_attr = fiber_attr_new();
 
 	header();
-	plan(10);
+	plan(11);
+
+	/*
+	 * Check the default fiber stack size value.
+	 */
+	ok(default_attr.stack_size == FIBER_STACK_SIZE_DEFAULT,
+	   "fiber_attr: the default stack size is %ld, but %d is set via CMake",
+	   default_attr.stack_size, FIBER_STACK_SIZE_DEFAULT);
 
 	/*
 	 * Set non-default stack size to prevent reusing of an
 	 * existing fiber.
 	 */
-	struct fiber_attr *fiber_attr = fiber_attr_new();
 	fiber_attr_setstacksize(fiber_attr, default_attr.stack_size * 2);
 
 	/*
-- 
GitLab