For Windows, GCC can be configured with `--enable-tls` to enable native TLS. The native TLS implementation has a limitation that it is incapable of exporting thread-local variables from DLLs. Therefore, they are retrieved via getter functions instead.
libstdc++-v3/ChangeLog:
* config/os/mingw32-w64/os_defines.h (_GLIBCXX_NO_EXTERN_THREAD_LOCAL):
New
macro.
* include/std/mutex (__get_once_callable): Declare function when
_GLIBCXX_NO_EXTERN_THREAD_LOCAL.
(__get_once_call): Likewise.
(__r_once_callable): New variable.
(__r_once_call): Likewise.
(once_flag::_Prepare_execution::_Prepare_execution): Use
__r_once_callable
and __r_once_call, instead of __once_callable and __r_once_call.
(once_flag::_Prepare_execution::~_Prepare_execution): Likewise.
* src/c++11/mutex.cc (__get_once_callable): Define function when
_GLIBCXX_NO_EXTERN_THREAD_LOCAL.
(__get_once_call): Likewise.
Signed-off-by: LIU Hao <[email protected]>
---
.../config/os/mingw32-w64/os_defines.h | 4 +++
libstdc++-v3/include/std/mutex | 26 ++++++++++++++++---
libstdc++-v3/src/c++11/mutex.cc | 14 ++++++++++
3 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/libstdc++-v3/config/os/mingw32-w64/os_defines.h
b/libstdc++-v3/config/os/mingw32-w64/os_defines.h
index 893cd704891b..70106fe792c6 100644
--- a/libstdc++-v3/config/os/mingw32-w64/os_defines.h
+++ b/libstdc++-v3/config/os/mingw32-w64/os_defines.h
@@ -96,4 +96,8 @@
// See libstdc++/94268
#define _GLIBCXX_BUFSIZ 4096
+// Use functions to access thread-local variables from a different module.
+// Windows does not support exporting thread-local data.
+#define _GLIBCXX_NO_EXTERN_THREAD_LOCAL 1
+
#endif
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index d4fc4c646488..59e65b10f42f 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -817,9 +817,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
# ifdef _GLIBCXX_HAVE_TLS
// If TLS is available use thread-local state for the type-erased callable
// that is being run by std::call_once in the current thread.
+# ifdef _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+
+ void*&
+ __get_once_callable() noexcept;
+
+ __typeof__(void (*)())&
+ __get_once_call() noexcept;
+
+ static void*& __r_once_callable = __get_once_callable();
+ static void (*&__r_once_call)() = __get_once_call();
+
+# else // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+
extern __thread void* __once_callable;
extern __thread void (*__once_call)();
+ static void*& __r_once_callable = __once_callable;
+ static void (*&__r_once_call)() = __once_call;
+
+# endif // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+
// RAII type to set up state for pthread_once call.
struct once_flag::_Prepare_execution
{
@@ -828,16 +846,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Prepare_execution(_Callable& __c)
{
// Store address in thread-local pointer:
- __once_callable = std::__addressof(__c);
+ __r_once_callable = std::__addressof(__c);
// Trampoline function to invoke the closure via thread-local pointer:
- __once_call = [] { (*static_cast<_Callable*>(__once_callable))(); };
+ __r_once_call = [] { (*static_cast<_Callable*>(__r_once_callable))(); };
}
~_Prepare_execution()
{
// PR libstdc++/82481
- __once_callable = nullptr;
- __once_call = nullptr;
+ __r_once_callable = nullptr;
+ __r_once_call = nullptr;
}
_Prepare_execution(const _Prepare_execution&) = delete;
diff --git a/libstdc++-v3/src/c++11/mutex.cc b/libstdc++-v3/src/c++11/mutex.cc
index d5da5c66ae99..82f0afa4cb4e 100644
--- a/libstdc++-v3/src/c++11/mutex.cc
+++ b/libstdc++-v3/src/c++11/mutex.cc
@@ -34,6 +34,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__thread void* __once_callable;
__thread void (*__once_call)();
+# ifdef _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+
+ // When thread-local variables can't be exported, these functions are called
+ // to retrieve these variables.
+ void*&
+ __get_once_callable() noexcept
+ { return __once_callable; }
+
+ __typeof__(void (*)())&
+ __get_once_call() noexcept
+ { return __once_call; }
+
+# endif // _GLIBCXX_NO_EXTERN_THREAD_LOCAL
+
extern "C" void __once_proxy()
{
// The caller stored a function pointer in __once_call. If it requires
--
2.52.0
From a066c3259d11098d3d34a7f212dcf4944ce42552 Mon Sep 17 00:00:00 2001 From: LIU Hao <[email protected]> Date: Wed, 3 Dec 2025 11:10:46 +0800 Subject: [PATCH] libstdc++: On Windows, retrieve thread-local variables via functions For Windows, GCC can be configured with `--enable-tls` to enable native TLS. The native TLS implementation has a limitation that it is incapable of exporting thread-local variables from DLLs. Therefore, they are retrieved via getter functions instead. libstdc++-v3/ChangeLog: * config/os/mingw32-w64/os_defines.h (_GLIBCXX_NO_EXTERN_THREAD_LOCAL): New macro. * include/std/mutex (__get_once_callable): Declare function when _GLIBCXX_NO_EXTERN_THREAD_LOCAL. (__get_once_call): Likewise. (__r_once_callable): New variable. (__r_once_call): Likewise. (once_flag::_Prepare_execution::_Prepare_execution): Use __r_once_callable and __r_once_call, instead of __once_callable and __r_once_call. (once_flag::_Prepare_execution::~_Prepare_execution): Likewise. * src/c++11/mutex.cc (__get_once_callable): Define function when _GLIBCXX_NO_EXTERN_THREAD_LOCAL. (__get_once_call): Likewise. Signed-off-by: LIU Hao <[email protected]> --- .../config/os/mingw32-w64/os_defines.h | 4 +++ libstdc++-v3/include/std/mutex | 26 ++++++++++++++++--- libstdc++-v3/src/c++11/mutex.cc | 14 ++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/config/os/mingw32-w64/os_defines.h b/libstdc++-v3/config/os/mingw32-w64/os_defines.h index 893cd704891b..70106fe792c6 100644 --- a/libstdc++-v3/config/os/mingw32-w64/os_defines.h +++ b/libstdc++-v3/config/os/mingw32-w64/os_defines.h @@ -96,4 +96,8 @@ // See libstdc++/94268 #define _GLIBCXX_BUFSIZ 4096 +// Use functions to access thread-local variables from a different module. +// Windows does not support exporting thread-local data. +#define _GLIBCXX_NO_EXTERN_THREAD_LOCAL 1 + #endif diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index d4fc4c646488..59e65b10f42f 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -817,9 +817,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION # ifdef _GLIBCXX_HAVE_TLS // If TLS is available use thread-local state for the type-erased callable // that is being run by std::call_once in the current thread. +# ifdef _GLIBCXX_NO_EXTERN_THREAD_LOCAL + + void*& + __get_once_callable() noexcept; + + __typeof__(void (*)())& + __get_once_call() noexcept; + + static void*& __r_once_callable = __get_once_callable(); + static void (*&__r_once_call)() = __get_once_call(); + +# else // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL + extern __thread void* __once_callable; extern __thread void (*__once_call)(); + static void*& __r_once_callable = __once_callable; + static void (*&__r_once_call)() = __once_call; + +# endif // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL + // RAII type to set up state for pthread_once call. struct once_flag::_Prepare_execution { @@ -828,16 +846,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Prepare_execution(_Callable& __c) { // Store address in thread-local pointer: - __once_callable = std::__addressof(__c); + __r_once_callable = std::__addressof(__c); // Trampoline function to invoke the closure via thread-local pointer: - __once_call = [] { (*static_cast<_Callable*>(__once_callable))(); }; + __r_once_call = [] { (*static_cast<_Callable*>(__r_once_callable))(); }; } ~_Prepare_execution() { // PR libstdc++/82481 - __once_callable = nullptr; - __once_call = nullptr; + __r_once_callable = nullptr; + __r_once_call = nullptr; } _Prepare_execution(const _Prepare_execution&) = delete; diff --git a/libstdc++-v3/src/c++11/mutex.cc b/libstdc++-v3/src/c++11/mutex.cc index d5da5c66ae99..82f0afa4cb4e 100644 --- a/libstdc++-v3/src/c++11/mutex.cc +++ b/libstdc++-v3/src/c++11/mutex.cc @@ -34,6 +34,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __thread void* __once_callable; __thread void (*__once_call)(); +# ifdef _GLIBCXX_NO_EXTERN_THREAD_LOCAL + + // When thread-local variables can't be exported, these functions are called + // to retrieve these variables. + void*& + __get_once_callable() noexcept + { return __once_callable; } + + __typeof__(void (*)())& + __get_once_call() noexcept + { return __once_call; } + +# endif // _GLIBCXX_NO_EXTERN_THREAD_LOCAL + extern "C" void __once_proxy() { // The caller stored a function pointer in __once_call. If it requires -- 2.52.0
OpenPGP_signature.asc
Description: OpenPGP digital signature
