https://gcc.gnu.org/g:7ad39bc909d1b425d0fa1803dc53cd741c10150f
commit r16-6251-g7ad39bc909d1b425d0fa1803dc53cd741c10150f Author: LIU Hao <[email protected]> Date: Wed Dec 3 11:10:46 2025 +0800 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 [_GLIBCXX_NO_EXTERN_THREAD_LOCAL] (__get_once_callable, __get_once_call): Declare new functions. * src/c++11/mutex.cc [_GLIBCXX_NO_EXTERN_THREAD_LOCAL] (__get_once_callable, __get_once_call): Define. Signed-off-by: LIU Hao <[email protected]> Co-authored-by: Jonathan Wakely <[email protected]> Diff: --- libstdc++-v3/config/os/mingw32-w64/os_defines.h | 4 ++++ libstdc++-v3/include/std/mutex | 19 +++++++++++++++++++ libstdc++-v3/src/c++11/mutex.cc | 14 ++++++++++++++ 3 files changed, 37 insertions(+) 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..e29fc7503171 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -817,9 +817,25 @@ _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; + + std::add_lvalue_reference<void (*)()>::type + __get_once_call() noexcept; + + // These macros mean that all the code below uses the same syntax: +#define __once_callable __get_once_callable() +#define __once_call __get_once_call() + +# else // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL + extern __thread void* __once_callable; extern __thread void (*__once_call)(); +# endif // ! _GLIBCXX_NO_EXTERN_THREAD_LOCAL + // RAII type to set up state for pthread_once call. struct once_flag::_Prepare_execution { @@ -844,6 +860,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Prepare_execution& operator=(const _Prepare_execution&) = delete; }; +#undef __once_callable +#undef __once_call + # else // Without TLS use a global std::mutex and store the callable in a // global std::function. 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
