[libc-commits] [libc] [libc] Remove (weak) __cxa_thread_finalize (PR #216081)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Sun Aug 16 09:34:11 PDT 2026
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/216081
>From 81f8775e60742e528d7f1863d84053e3f658c798 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 13 Aug 2026 14:57:38 +0000
Subject: [PATCH 1/3] [libc] Remove (weak) __cxa_thread_finalize
Unlike __cxa_thread_atexit(_impl), this function is not a part of the
ABI as the process of calling the thread exit callbacks is an
implementation detail. Additionally, the weak definition gets in the way
of refactoring the thread code as the linker will not extract an object
from the archive if the dependency is already satisfied by a weak
definition.
Instead of a weak definition, I use a preprocessor macro to determine
whether we need to call the thread cleanup function (i.e., whether the
target supports threads).
---
libc/src/__support/threads/thread.cpp | 2 --
libc/src/stdlib/CMakeLists.txt | 10 ++++++++++
libc/src/stdlib/exit.cpp | 24 +++++++-----------------
3 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/libc/src/__support/threads/thread.cpp b/libc/src/__support/threads/thread.cpp
index babcfdc5aea15..31c230a45b573 100644
--- a/libc/src/__support/threads/thread.cpp
+++ b/libc/src/__support/threads/thread.cpp
@@ -164,8 +164,6 @@ void call_atexit_callbacks(ThreadAttributes *attrib) {
}
}
-extern "C" void __cxa_thread_finalize() { call_atexit_callbacks(self.attrib); }
-
} // namespace internal
cpp::optional<unsigned int> new_tss_key(TSSDtor *dtor) {
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index a0e8cd356a212..1d45a70d1a26f 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -811,12 +811,22 @@ if(NOT LIBC_TARGET_OS_IS_BAREMETAL)
)
endif()
+set(exit_compile_options "")
+if(TARGET libc.src.__support.threads.thread)
+ list(APPEND exit_deps
+ libc.src.__support.threads.thread
+ )
+ libc_add_definition(exit_compile_options "LIBC_COPT_SUPPORT_THREADS")
+endif()
+
add_entrypoint_object(
exit
SRCS
exit.cpp
HDRS
exit.h
+ COMPILE_OPTIONS
+ ${exit_compile_options}
DEPENDS
${exit_deps}
)
diff --git a/libc/src/stdlib/exit.cpp b/libc/src/stdlib/exit.cpp
index db6a8f1280902..6f6758aba5896 100644
--- a/libc/src/stdlib/exit.cpp
+++ b/libc/src/stdlib/exit.cpp
@@ -11,29 +11,19 @@
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
+#ifdef LIBC_COPT_SUPPORT_THREADS
+#include "src/__support/threads/thread.h"
+#endif
+
namespace LIBC_NAMESPACE_DECL {
extern "C" void __cxa_finalize(void *);
-// exit() needs to clean up TLS and call associated destructors.
-//
-// The weak no-op implementation is in the same TU with its caller for the case
-// where the real definition is not linked in. This is preferable over weak
-// undefined symbol with a check since that requires a GOT slot.
-//
-// The strong implementation is in libc/src/__support/threads/thread.cpp
-// but not every platform supports threads (e.g. baremetal) in which case the
-// the no-op implementation is sufficient.
-//
-// TODO: Strictly speaking, it is not valid to call exit in overlay mode
-// as we have no way to ensure system libc will call the TLS destructors.
-// We should run exit related tests in hermetic mode but this is currently
-// blocked by https://github.com/llvm/llvm-project/issues/133925.
-extern "C" [[gnu::weak]] void __cxa_thread_finalize() {}
-
// TODO: use recursive mutex to protect this routine.
[[noreturn]] LLVM_LIBC_FUNCTION(void, exit, (int status)) {
- __cxa_thread_finalize();
+#ifdef LIBC_COPT_SUPPORT_THREADS
+ internal::call_atexit_callbacks(self.attrib);
+#endif
__cxa_finalize(nullptr);
internal::exit(status);
}
>From cd5c6a1641e1646e6ac52c902667b9989add9f06 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 13 Aug 2026 17:34:37 +0000
Subject: [PATCH 2/3] add comment
---
libc/src/stdlib/exit.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/libc/src/stdlib/exit.cpp b/libc/src/stdlib/exit.cpp
index 6f6758aba5896..580519237761a 100644
--- a/libc/src/stdlib/exit.cpp
+++ b/libc/src/stdlib/exit.cpp
@@ -22,6 +22,7 @@ extern "C" void __cxa_finalize(void *);
// TODO: use recursive mutex to protect this routine.
[[noreturn]] LLVM_LIBC_FUNCTION(void, exit, (int status)) {
#ifdef LIBC_COPT_SUPPORT_THREADS
+ // Call TLS destructors, if supported by the target.
internal::call_atexit_callbacks(self.attrib);
#endif
__cxa_finalize(nullptr);
>From 90152892b39b12d455fa352ed13ba4a63f8486e1 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Sun, 16 Aug 2026 18:34:00 +0200
Subject: [PATCH 3/3] Add TODO
---
libc/src/stdlib/CMakeLists.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 1d45a70d1a26f..af2cad21028d5 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -812,6 +812,8 @@ if(NOT LIBC_TARGET_OS_IS_BAREMETAL)
endif()
set(exit_compile_options "")
+# TODO: Revisit this when/if LIBC_CONF_THREAD_MODE controls more than the
+# mutex implementation.
if(TARGET libc.src.__support.threads.thread)
list(APPEND exit_deps
libc.src.__support.threads.thread
More information about the libc-commits
mailing list