From 9f925f3b198e210e0d124a3c69fae034f429942f Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 3 Nov 2020 19:42:07 +0000 Subject: [PATCH] libstdc++: Refactor std::call_once internals This separates the definition of std::__call_proxy into two funcions, one for TLS and one for non-TLS, to make them easier to read. It also replaces the __get_once_functor_lock_ptr() internal helper with a new set_lock_ptr(unique_lock*) function so that __once_proxy doesn't need to call it twice. libstdc++-v3/ChangeLog: * src/c++11/mutex.cc [_GLIBCXX_HAVE_TLS] (__once_proxy): Define separately for TLS targets. [!_GLIBCXX_HAVE_TLS] (__get_once_functor_lock_ptr): Replace with ... (set_lock_ptr): ... this. Set new value and return previous value. [!_GLIBCXX_HAVE_TLS] (__set_once_functor_lock_ptr): Adjust to use set_lock_ptr. [!_GLIBCXX_HAVE_TLS] (__once_proxy): Likewise. --- libstdc++-v3/src/c++11/mutex.cc | 68 +++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/libstdc++-v3/src/c++11/mutex.cc b/libstdc++-v3/src/c++11/mutex.cc index 286f77f9a45..4d42bed8ecc 100644 --- a/libstdc++-v3/src/c++11/mutex.cc +++ b/libstdc++-v3/src/c++11/mutex.cc @@ -84,18 +84,6 @@ std::once_flag::_M_finish(bool returning) noexcept #endif // ! FUTEX -#ifndef _GLIBCXX_HAVE_TLS -namespace -{ - inline std::unique_lock*& - __get_once_functor_lock_ptr() - { - static std::unique_lock* __once_functor_lock_ptr = 0; - return __once_functor_lock_ptr; - } -} -#endif - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -103,9 +91,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef _GLIBCXX_HAVE_TLS __thread void* __once_callable; __thread void (*__once_call)(); -#else + + extern "C" void __once_proxy() + { + // The caller stored a function pointer in __once_call. If it requires + // any state, it gets it from __once_callable. + __once_call(); + } + +#else // ! TLS + // Explicit instantiation due to -fno-implicit-instantiation. template class function; + function __once_functor; mutex& @@ -115,11 +113,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return once_mutex; } +namespace +{ + // Store ptr in a global variable and return the previous value. + inline unique_lock* + set_lock_ptr(unique_lock* ptr) + { + static unique_lock* __once_functor_lock_ptr = nullptr; + return std::__exchange(__once_functor_lock_ptr, ptr); + } +} + // code linked against ABI 3.4.12 and later uses this void __set_once_functor_lock_ptr(unique_lock* __ptr) { - __get_once_functor_lock_ptr() = __ptr; + (void) set_lock_ptr(__ptr); } // unsafe - retained for compatibility with ABI 3.4.11 @@ -129,26 +138,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static unique_lock once_functor_lock(__get_once_mutex(), defer_lock); return once_functor_lock; } -#endif - extern "C" + // This is called via pthread_once while __get_once_mutex() is locked. + extern "C" void + __once_proxy() { - void __once_proxy() + // Get the callable out of the global functor. + function callable = std::move(__once_functor); + + // Then unlock the global mutex + if (unique_lock* lock = set_lock_ptr(nullptr)) { -#ifndef _GLIBCXX_HAVE_TLS - function __once_call = std::move(__once_functor); - if (unique_lock* __lock = __get_once_functor_lock_ptr()) - { - // caller is using new ABI and provided lock ptr - __get_once_functor_lock_ptr() = 0; - __lock->unlock(); - } - else - __get_once_functor_lock().unlock(); // global lock -#endif - __once_call(); + // Caller is using the new ABI and provided a pointer to its lock. + lock->unlock(); } + else + __get_once_functor_lock().unlock(); // global lock + + // Finally, invoke the callable. + callable(); } +#endif // ! TLS _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -- 2.30.2