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 <lh_mouse@126.com>
Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
This commit is contained in:
LIU Hao
2025-12-03 11:10:46 +08:00
committed by Jonathan Wakely
parent 4d6a437261
commit 7ad39bc909
3 changed files with 37 additions and 0 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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