From 637e3668fdc17c4e226538fb14f9fab225433d01 Mon Sep 17 00:00:00 2001
From: Jonathan Wakely
Date: Wed, 5 Oct 2022 21:21:54 +0100
Subject: [PATCH] libstdc++: Allow emergency EH alloc pool size to be tuned
[PR68606]
Implement a long-standing request to support tuning the size of the
emergency buffer for allocating exceptions after malloc fails, or to
disable that buffer entirely.
It's now possible to disable the dynamic allocation of the buffer and
use a fixed-size static buffer, via --enable-libstdcxx-static-eh-pool.
This is a built-time choice that is baked into libstdc++ and so affects
all code linked against that build of libstdc++.
The size of the pool can be set by --with-libstdcxx-eh-pool-obj-count=N
which is measured in units of sizeof(void*) not bytes. A given exception
type such as std::system_error depends on the target, so giving a size
in bytes wouldn't be portable across 16/32/64-bit targets.
When libstdc++ is configured to use a dynamic buffer, the size of that
buffer can now be tuned at runtime by setting the GLIBCXX_TUNABLES
environment variable (c.f. PR libstdc++/88264). The number of exceptions
to reserve space for is controlled by the "glibcxx.eh_pool.obj_count"
and "glibcxx.eh_pool.obj_size" tunables. The pool will be sized to be
able to allocate obj_count exceptions of size obj_size*sizeof(void*) and
obj_count "dependent" exceptions rethrown by std::rethrow_exception.
With the ability to tune the buffer size, we can reduce the default pool
size on 32-bit and 16-bit targets. Most users never need to throw 1kB
exceptions in parallel from hundreds of threads after malloc is OOM. The
users who do need that can use the tunables to select larger sizes.
The old defaults can be chosen at runtime by setting GLIBCXX_TUNABLES
to:
64-bit: glibcxx.eh_pool.obj_count=64:glibcxx.eh_pool.obj_size=112
32-bit: glibcxx.eh_pool.obj_count=32:glibcxx.eh_pool.obj_size=104
Or approximated by configuring with:
64-bit: --with-libstdcxx-eh-pool-obj-count=252
32-bit: --with-libstdcxx-eh-pool-obj-count=94
libstdc++-v3/ChangeLog:
PR libstdc++/68606
* Makefile.in: Regenerate.
* acinclude.m4 (GLIBCXX_EMERGENCY_EH_ALLOC): New macro.
* configure: Regenerate.
* configure.ac: Use GLIBCXX_EMERGENCY_EH_ALLOC.
* crossconfig.m4: Check for secure_getenv.
* doc/Makefile.in: Regenerate.
* doc/xml/manual/configure.xml: Document new configure options.
* doc/xml/manual/evolution.xml: Document addition of tunables.
* doc/xml/manual/using_exceptions.xml: Document emergency
buffer and tunables.
* doc/html/*: Regenerate.
* include/Makefile.in: Regenerate.
* libsupc++/Makefile.am: Use EH_POOL_FLAGS.
* libsupc++/Makefile.in: Regenerate.
* libsupc++/eh_alloc.cc (EMERGENCY_OBJ_SIZE): Define in units
of sizeof(void*) not including the ABI's exception header.
(EMERGENCY_OBJ_COUNT): Define as target-independent calculation
based on word size.
(MAX_OBJ_COUNT): Define macro for upper limit on pool size.
(pool) [_GLIBCXX_EH_POOL_STATIC]: Use fixed-size buffer.
(pool::buffer_size_in_bytes): New static member function.
(pool::pool): Parse GLIBCXX_TUNABLES environment variable to set
pool size at runtime.
(pool::in_pool): Use std::less for total order.
(__freeres) [_GLIBCXX_EH_POOL_STATIC]: Do nothing.
(__cxa_free_exception, __cxa_free_dependent_exception): Add
[[unlikely]] attributes.
* po/Makefile.in: Regenerate.
* python/Makefile.in: Regenerate.
* src/Makefile.in: Regenerate.
* src/c++11/Makefile.in: Regenerate.
* src/c++17/Makefile.in: Regenerate.
* src/c++20/Makefile.in: Regenerate.
* src/c++98/Makefile.in: Regenerate.
* src/filesystem/Makefile.in: Regenerate.
* src/libbacktrace/Makefile.in: Regenerate.
* testsuite/Makefile.in: Regenerate.
---
libstdc++-v3/Makefile.in | 1 +
libstdc++-v3/acinclude.m4 | 45 ++++
libstdc++-v3/configure | 67 +++++-
libstdc++-v3/configure.ac | 3 +
libstdc++-v3/crossconfig.m4 | 1 +
libstdc++-v3/doc/Makefile.in | 1 +
libstdc++-v3/doc/html/index.html | 4 +-
libstdc++-v3/doc/html/manual/api.html | 3 +
libstdc++-v3/doc/html/manual/appendix.html | 2 +-
.../doc/html/manual/appendix_porting.html | 2 +-
libstdc++-v3/doc/html/manual/configure.html | 10 +-
libstdc++-v3/doc/html/manual/index.html | 4 +-
libstdc++-v3/doc/html/manual/intro.html | 2 +-
libstdc++-v3/doc/html/manual/using.html | 2 +-
.../doc/html/manual/using_exceptions.html | 77 +++++-
libstdc++-v3/doc/xml/manual/configure.xml | 23 ++
libstdc++-v3/doc/xml/manual/evolution.xml | 9 +
.../doc/xml/manual/using_exceptions.xml | 90 +++++++
libstdc++-v3/include/Makefile.in | 1 +
libstdc++-v3/libsupc++/Makefile.am | 2 +-
libstdc++-v3/libsupc++/Makefile.in | 3 +-
libstdc++-v3/libsupc++/eh_alloc.cc | 225 +++++++++++++-----
libstdc++-v3/po/Makefile.in | 1 +
libstdc++-v3/python/Makefile.in | 1 +
libstdc++-v3/src/Makefile.in | 1 +
libstdc++-v3/src/c++11/Makefile.in | 1 +
libstdc++-v3/src/c++17/Makefile.in | 1 +
libstdc++-v3/src/c++20/Makefile.in | 1 +
libstdc++-v3/src/c++98/Makefile.in | 1 +
libstdc++-v3/src/filesystem/Makefile.in | 1 +
libstdc++-v3/src/libbacktrace/Makefile.in | 1 +
libstdc++-v3/testsuite/Makefile.in | 1 +
32 files changed, 494 insertions(+), 93 deletions(-)
diff --git a/libstdc++-v3/Makefile.in b/libstdc++-v3/Makefile.in
index 58a0acdcc1b..a7c2b60678b 100644
--- a/libstdc++-v3/Makefile.in
+++ b/libstdc++-v3/Makefile.in
@@ -240,6 +240,7 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+EH_POOL_FLAGS = @EH_POOL_FLAGS@
ERROR_CONSTANTS_SRCDIR = @ERROR_CONSTANTS_SRCDIR@
EXEEXT = @EXEEXT@
EXTRA_CFLAGS = @EXTRA_CFLAGS@
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 719eab15c77..6523ba9a816 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -5092,6 +5092,51 @@ BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DBACKTRACE_ELF_SIZE=$elfsize"
GLIBCXX_CONDITIONAL(ENABLE_BACKTRACE, [test "$enable_libstdcxx_backtrace" = yes])
])
+dnl
+dnl Allow the emergency EH pool to be configured.
+dnl
+dnl --enable-libstdcxx-static-eh-pool will cause a fixed-size static buffer
+dnl to be used for allocating exceptions after malloc fails. The default is
+dnl to allocate a buffer using malloc
+dnl
+dnl --with-libstdcxx-eh-pool-obj-count=N will set the default size for the
+dnl buffer. For a static buffer that size is fixed permanently. For a dynamic
+dnl buffer it's the default, but it can be overridden from the environment.
+dnl
+dnl To set the default to approximately the same values as GCC 12,
+dnl use --with-libstdcxx-eh-pool-obj-count=94 for 32-bit targets,
+dnl and --with-libstdcxx-eh-pool-obj-count=252 for 64-bit targets.
+dnl
+dnl Defines:
+dnl _GLIBCXX_EH_POOL_STATIC if a fixed-size static buffer should be used
+dnl instead of allocating a buffer on startup.
+dnl _GLIBCXX_EH_POOL_NOBJS to override the default EMERGENCY_OBJ_COUNT value.
+dnl
+AC_DEFUN([GLIBCXX_EMERGENCY_EH_ALLOC], [
+ eh_pool_static=
+ eh_pool_nobjs=
+ AC_ARG_ENABLE([libstdcxx-static-eh-pool],
+ AC_HELP_STRING([--enable-libstdcxx-static-eh-pool],
+ [use a fixed-size static buffer for allocating exceptions if malloc fails]),
+ [if test "${enableval}" = yes; then
+ eh_pool_static="-D_GLIBCXX_EH_POOL_STATIC"
+ AC_MSG_NOTICE([EH pool using static buffer])
+ fi],)
+
+ AC_ARG_WITH([libstdcxx-eh-pool-obj-count],
+ AC_HELP_STRING([--with-libstdcxx-eh-pool-obj-count],
+ [the number of exceptions that can be allocated from the pool if malloc fails]),
+ [if test "${withval}" -ge 0 2>/dev/null; then
+ eh_pool_obj_count="-D_GLIBCXX_EH_POOL_NOBJS=${withval}"
+ AC_MSG_NOTICE([EH pool object count: ${withval}])
+ else
+ AC_MSG_ERROR([EH pool obj count must be a non-negative integer: $withval])
+ fi],)
+
+ EH_POOL_FLAGS="$eh_pool_static $eh_pool_obj_count"
+ AC_SUBST(EH_POOL_FLAGS)
+])
+
# Macros from the top-level gcc directory.
m4_include([../config/gc++filt.m4])
m4_include([../config/tls.m4])
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 4bb1d73f0e0..b564175a040 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -675,6 +675,7 @@ DOT
DOXYGEN
BUILD_INFO_FALSE
BUILD_INFO_TRUE
+EH_POOL_FLAGS
ENABLE_BACKTRACE_FALSE
ENABLE_BACKTRACE_TRUE
BACKTRACE_SUPPORTS_THREADS
@@ -958,6 +959,8 @@ with_default_libstdcxx_abi
enable_libstdcxx_threads
enable_libstdcxx_filesystem_ts
enable_libstdcxx_backtrace
+enable_libstdcxx_static_eh_pool
+with_libstdcxx_eh_pool_obj_count
enable_cet
with_gxx_include_dir
enable_version_specific_runtime_libs
@@ -1668,6 +1671,9 @@ Optional Features:
turns on ISO/IEC TS 18822 support [default=auto]
--enable-libstdcxx-backtrace
turns on libbacktrace support [default=auto]
+ --enable-libstdcxx-static-eh-pool
+ use a fixed-size static buffer for allocating
+ exceptions if malloc fails
--enable-cet enable Intel CET in target libraries [default=auto]
--enable-version-specific-runtime-libs
Specify that runtime libraries should be installed
@@ -1695,6 +1701,9 @@ Optional Packages:
--with-system-libunwind use installed libunwind
--with-default-libstdcxx-abi
set the std::string ABI to use by default
+ --with-libstdcxx-eh-pool-obj-count
+ the number of exceptions that can be allocated from
+ the pool if malloc fails
--with-gxx-include-dir=DIR
installation directory for include files
--with-toolexeclibdir=DIR
@@ -12227,7 +12236,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12206 "configure"
+#line 12215 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12333,7 +12342,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12312 "configure"
+#line 12321 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -16053,7 +16062,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; }
# Fake what AC_TRY_COMPILE does.
cat > conftest.$ac_ext << EOF
-#line 16012 "configure"
+#line 16021 "configure"
int main()
{
typedef bool atomic_type;
@@ -16088,7 +16097,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; }
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 16047 "configure"
+#line 16056 "configure"
int main()
{
typedef short atomic_type;
@@ -16123,7 +16132,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; }
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 16082 "configure"
+#line 16091 "configure"
int main()
{
// NB: _Atomic_word not necessarily int.
@@ -16159,7 +16168,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; }
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 16118 "configure"
+#line 16127 "configure"
int main()
{
typedef long long atomic_type;
@@ -16315,7 +16324,7 @@ $as_echo "mutex" >&6; }
# unnecessary for this test.
cat > conftest.$ac_ext << EOF
-#line 16274 "configure"
+#line 16283 "configure"
int main()
{
_Decimal32 d1;
@@ -16357,7 +16366,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
# unnecessary for this test.
cat > conftest.$ac_ext << EOF
-#line 16316 "configure"
+#line 16325 "configure"
template
struct same
{ typedef T2 type; };
@@ -54268,6 +54277,17 @@ _ACEOF
fi
done
+ for ac_func in secure_getenv
+do :
+ ac_fn_c_check_func "$LINENO" "secure_getenv" "ac_cv_func_secure_getenv"
+if test "x$ac_cv_func_secure_getenv" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SECURE_GETENV 1
+_ACEOF
+
+fi
+done
+
@@ -71916,6 +71936,37 @@ $as_echo "7.1.0" >&6; }
fi
+# For libsupc++/eh_alloc.cc defaults.
+
+ eh_pool_static=
+ eh_pool_nobjs=
+ # Check whether --enable-libstdcxx-static-eh-pool was given.
+if test "${enable_libstdcxx_static_eh_pool+set}" = set; then :
+ enableval=$enable_libstdcxx_static_eh_pool; if test "${enableval}" = yes; then
+ eh_pool_static="-D_GLIBCXX_EH_POOL_STATIC"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: EH pool using static buffer" >&5
+$as_echo "$as_me: EH pool using static buffer" >&6;}
+ fi
+fi
+
+
+
+# Check whether --with-libstdcxx-eh-pool-obj-count was given.
+if test "${with_libstdcxx_eh_pool_obj_count+set}" = set; then :
+ withval=$with_libstdcxx_eh_pool_obj_count; if test "${withval}" -ge 0 2>/dev/null; then
+ eh_pool_obj_count="-D_GLIBCXX_EH_POOL_NOBJS=${withval}"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: EH pool object count: ${withval}" >&5
+$as_echo "$as_me: EH pool object count: ${withval}" >&6;}
+ else
+ as_fn_error $? "EH pool obj count must be a non-negative integer: $withval" "$LINENO" 5
+ fi
+fi
+
+
+ EH_POOL_FLAGS="$eh_pool_static $eh_pool_obj_count"
+
+
+
# Define documentation rules conditionally.
# See if makeinfo has been installed and is modern enough
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index c05fcdda7e9..42c453099f2 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -538,6 +538,9 @@ GLIBCXX_CHECK_SIZE_T_MANGLING
# Check which release added std::exception_ptr for the target
GLIBCXX_CHECK_EXCEPTION_PTR_SYMVER
+# For libsupc++/eh_alloc.cc defaults.
+GLIBCXX_EMERGENCY_EH_ALLOC
+
# Define documentation rules conditionally.
# See if makeinfo has been installed and is modern enough
diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4
index 130f47fb1d4..b3269cb88e0 100644
--- a/libstdc++-v3/crossconfig.m4
+++ b/libstdc++-v3/crossconfig.m4
@@ -187,6 +187,7 @@ case "${host}" in
AC_CHECK_FUNCS(timespec_get)
AC_CHECK_FUNCS(sockatmark)
AC_CHECK_FUNCS(uselocale)
+ AC_CHECK_FUNCS(secure_getenv)
AM_ICONV
;;
*-mingw32*)
diff --git a/libstdc++-v3/doc/Makefile.in b/libstdc++-v3/doc/Makefile.in
index 6aaceea7491..469a6082c88 100644
--- a/libstdc++-v3/doc/Makefile.in
+++ b/libstdc++-v3/doc/Makefile.in
@@ -199,6 +199,7 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+EH_POOL_FLAGS = @EH_POOL_FLAGS@
ERROR_CONSTANTS_SRCDIR = @ERROR_CONSTANTS_SRCDIR@
EXEEXT = @EXEEXT@
EXTRA_CFLAGS = @EXTRA_CFLAGS@
diff --git a/libstdc++-v3/doc/html/index.html b/libstdc++-v3/doc/html/index.html
index 1e0cecbcc4f..ce951e6cc8e 100644
--- a/libstdc++-v3/doc/html/index.html
+++ b/libstdc++-v3/doc/html/index.html
@@ -23,7 +23,7 @@
Calling a std::bind
result as volatile is ill-formed for C++20
and later.
+
+Tunables <variable>glibcxx.eh_pool.obj_count</variable> and
+<variable>glibcxx.eh_pool.obj_size</variable> were added.