From: LIU Hao <[email protected]>
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]>
---
v3: Used macros to reduce the impact of the changes. Use
add_lvalue_reference for return type.
Tested x86_64-linux. Built on x86_64-w64-mingw64.
Pushed to trunk.
.../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
--
2.52.0